]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/capsicum-test/sctp.cc
ipfw(8): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / contrib / capsicum-test / sctp.cc
1 // Tests of SCTP functionality
2 // Requires: libsctp-dev package on Debian Linux, CONFIG_IP_SCTP in kernel config
3 #ifdef HAVE_SCTP
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <netinet/sctp.h>
8 #include <arpa/inet.h>
9 #include <stdio.h>
10
11 #include "syscalls.h"
12 #include "capsicum.h"
13 #include "capsicum-test.h"
14
15 static cap_rights_t r_ro;
16 static cap_rights_t r_wo;
17 static cap_rights_t r_rw;
18 static cap_rights_t r_all;
19 static cap_rights_t r_all_nopeel;
20 #define DO_PEELOFF 0x1A
21 #define DO_TERM    0x1B
22
23 static int SctpClient(int port, unsigned char byte) {
24   // Create sockets
25   int sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
26   EXPECT_OK(sock);
27   if (sock < 0) return sock;
28   int cap_sock_ro = dup(sock);
29   EXPECT_OK(cap_sock_ro);
30   EXPECT_OK(cap_rights_limit(cap_sock_ro, &r_rw));
31   int cap_sock_rw = dup(sock);
32   EXPECT_OK(cap_sock_rw);
33   EXPECT_OK(cap_rights_limit(cap_sock_rw, &r_rw));
34   int cap_sock_all = dup(sock);
35   EXPECT_OK(cap_sock_all);
36   EXPECT_OK(cap_rights_limit(cap_sock_all, &r_all));
37   close(sock);
38
39   // Send a message.  Requires CAP_WRITE and CAP_CONNECT.
40   struct sockaddr_in serv_addr;
41   memset(&serv_addr, 0, sizeof(serv_addr));
42   serv_addr.sin_family = AF_INET;
43   serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
44   serv_addr.sin_port = htons(port);
45
46   EXPECT_NOTCAPABLE(sctp_sendmsg(cap_sock_ro, &byte, 1,
47                                  (struct sockaddr*)&serv_addr, sizeof(serv_addr),
48                                  0, 0, 1, 0, 0));
49   EXPECT_NOTCAPABLE(sctp_sendmsg(cap_sock_rw, &byte, 1,
50                                  (struct sockaddr*)&serv_addr, sizeof(serv_addr),
51                                  0, 0, 1, 0, 0));
52   if (verbose) fprintf(stderr, "  [%d]sctp_sendmsg(%02x)\n", getpid_(), byte);
53   EXPECT_OK(sctp_sendmsg(cap_sock_all, &byte, 1,
54                          (struct sockaddr*)&serv_addr, sizeof(serv_addr),
55                          0, 0, 1, 0, 0));
56   close(cap_sock_ro);
57   close(cap_sock_rw);
58   return cap_sock_all;
59 }
60
61
62 TEST(Sctp, Socket) {
63   int sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
64   EXPECT_OK(sock);
65   if (sock < 0) return;
66
67   cap_rights_init(&r_ro, CAP_READ);
68   cap_rights_init(&r_wo, CAP_WRITE);
69   cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
70   cap_rights_init(&r_all, CAP_READ, CAP_WRITE, CAP_SOCK_CLIENT, CAP_SOCK_SERVER);
71   cap_rights_init(&r_all_nopeel, CAP_READ, CAP_WRITE, CAP_SOCK_CLIENT, CAP_SOCK_SERVER);
72   cap_rights_clear(&r_all_nopeel, CAP_PEELOFF);
73
74   int cap_sock_wo = dup(sock);
75   EXPECT_OK(cap_sock_wo);
76   EXPECT_OK(cap_rights_limit(cap_sock_wo, &r_wo));
77   int cap_sock_rw = dup(sock);
78   EXPECT_OK(cap_sock_rw);
79   EXPECT_OK(cap_rights_limit(cap_sock_rw, &r_rw));
80   int cap_sock_all = dup(sock);
81   EXPECT_OK(cap_sock_all);
82   EXPECT_OK(cap_rights_limit(cap_sock_all, &r_all));
83   int cap_sock_all_nopeel = dup(sock);
84   EXPECT_OK(cap_sock_all_nopeel);
85   EXPECT_OK(cap_rights_limit(cap_sock_all_nopeel, &r_all_nopeel));
86   close(sock);
87
88   struct sockaddr_in addr;
89   memset(&addr, 0, sizeof(addr));
90   addr.sin_family = AF_INET;
91   addr.sin_port = htons(0);
92   addr.sin_addr.s_addr = htonl(INADDR_ANY);
93   socklen_t len = sizeof(addr);
94
95   // Can only bind the fully-capable socket.
96   EXPECT_NOTCAPABLE(bind(cap_sock_rw, (struct sockaddr *)&addr, len));
97   EXPECT_OK(bind(cap_sock_all, (struct sockaddr *)&addr, len));
98
99   EXPECT_OK(getsockname(cap_sock_all, (struct sockaddr *)&addr, &len));
100   int port = ntohs(addr.sin_port);
101
102   // Now we know the port involved, fork off children to run clients.
103   pid_t child1 = fork();
104   if (child1 == 0) {
105     // Child process 1: wait for server setup
106     sleep(1);
107     // Send a message that triggers peeloff
108     int client_sock = SctpClient(port, DO_PEELOFF);
109     sleep(1);
110     close(client_sock);
111     exit(HasFailure());
112   }
113
114   pid_t child2 = fork();
115   if (child2 == 0) {
116     // Child process 2: wait for server setup
117     sleep(2);
118     // Send a message that triggers server exit
119     int client_sock = SctpClient(port, DO_TERM);
120     close(client_sock);
121     exit(HasFailure());
122   }
123
124   // Can only listen on the fully-capable socket.
125   EXPECT_NOTCAPABLE(listen(cap_sock_rw, 3));
126   EXPECT_OK(listen(cap_sock_all, 3));
127
128   // Can only do socket operations on the fully-capable socket.
129   len = sizeof(addr);
130   EXPECT_NOTCAPABLE(getsockname(cap_sock_rw, (struct sockaddr*)&addr, &len));
131
132   struct sctp_event_subscribe events;
133   memset(&events, 0, sizeof(events));
134   events.sctp_association_event = 1;
135   events.sctp_data_io_event = 1;
136   EXPECT_NOTCAPABLE(setsockopt(cap_sock_rw, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)));
137   len = sizeof(events);
138   EXPECT_NOTCAPABLE(getsockopt(cap_sock_rw, IPPROTO_SCTP, SCTP_EVENTS, &events, &len));
139   memset(&events, 0, sizeof(events));
140   events.sctp_association_event = 1;
141   events.sctp_data_io_event = 1;
142   EXPECT_OK(setsockopt(cap_sock_all, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)));
143   len = sizeof(events);
144   EXPECT_OK(getsockopt(cap_sock_all, IPPROTO_SCTP, SCTP_EVENTS, &events, &len));
145
146   len = sizeof(addr);
147   memset(&addr, 0, sizeof(addr));
148   EXPECT_OK(getsockname(cap_sock_all, (struct sockaddr*)&addr, &len));
149   EXPECT_EQ(AF_INET, addr.sin_family);
150   EXPECT_EQ(htons(port), addr.sin_port);
151
152   struct sockaddr_in client_addr;
153   socklen_t addr_len = sizeof(client_addr);
154   unsigned char buffer[1024];
155   struct sctp_sndrcvinfo sri;
156   memset(&sri, 0, sizeof(sri));
157   int flags = 0;
158   EXPECT_NOTCAPABLE(sctp_recvmsg(cap_sock_wo, buffer, sizeof(buffer),
159                                  (struct sockaddr*)&client_addr, &addr_len,
160                                  &sri, &flags));
161   while (true) {
162   retry:
163     memset(&sri, 0, sizeof(sri));
164     int len = sctp_recvmsg(cap_sock_rw, buffer, sizeof(buffer),
165                            (struct sockaddr*)&client_addr, &addr_len,
166                            &sri, &flags);
167     if (len < 0 && errno == EAGAIN) goto retry;
168     EXPECT_OK(len);
169     if (len > 0) {
170       if (verbose) fprintf(stderr, "[%d]sctp_recvmsg(%02x..)", getpid_(), (unsigned)buffer[0]);
171       if (buffer[0] == DO_PEELOFF) {
172         if (verbose) fprintf(stderr, "..peeling off association %08lx\n", (long)sri.sinfo_assoc_id);
173         // Peel off the association.  Needs CAP_PEELOFF.
174         int rc1 = sctp_peeloff(cap_sock_all_nopeel, sri.sinfo_assoc_id);
175         EXPECT_NOTCAPABLE(rc1);
176         int rc2 = sctp_peeloff(cap_sock_all, sri.sinfo_assoc_id);
177         EXPECT_OK(rc2);
178         int peeled = std::max(rc1, rc2);
179         if (peeled > 0) {
180 #ifdef CAP_FROM_PEELOFF
181           // Peeled off FD should have same rights as original socket.
182           cap_rights_t rights;
183           EXPECT_OK(cap_rights_get(peeled, &rights));
184           EXPECT_RIGHTS_EQ(&r_all, &rights);
185 #endif
186           close(peeled);
187         }
188       } else if (buffer[0] == DO_TERM) {
189         if (verbose) fprintf(stderr, "..terminating server\n");
190         break;
191       }
192     } else if (len < 0) {
193       break;
194     }
195   }
196
197   // Wait for the children.
198   int status;
199   int rc;
200   EXPECT_EQ(child1, waitpid(child1, &status, 0));
201   rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
202   EXPECT_EQ(0, rc);
203   EXPECT_EQ(child2, waitpid(child2, &status, 0));
204   rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
205   EXPECT_EQ(0, rc);
206
207   close(cap_sock_wo);
208   close(cap_sock_rw);
209   close(cap_sock_all);
210   close(cap_sock_all_nopeel);
211 }
212 #endif