]> git.saurik.com Git - apple/network_cmds.git/blame - ecnprobe/ecn_probe.c
network_cmds-543.200.16.tar.gz
[apple/network_cmds.git] / ecnprobe / ecn_probe.c
CommitLineData
89c4ed63
A
1/*
2 Copyright (c) 2000
3 International Computer Science Institute
4 All rights reserved.
5
6 This file may contain software code originally developed for the
7 Sting project. The Sting software carries the following copyright:
8
9 Copyright (c) 1998, 1999
10 Stefan Savage and the University of Washington.
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the distribution.
21 3. All advertising materials mentioning features or use of this software
22 must display the following acknowledgment:
23 This product includes software developed by ACIRI, the AT&T
24 Center for Internet Research at ICSI (the International Computer
25 Science Institute). This product may also include software developed
26 by Stefan Savage at the University of Washington.
27 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
28 may not be used to endorse or promote products derived from this software
29 without specific prior written permission.
30
31 THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
32 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ARE DISCLAIMED. IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
35 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 SUCH DAMAGE.
42*/
43
44#include <sys/types.h>
45#include <sys/param.h>
46#include <sys/time.h>
47#include <string.h>
48#include <stdio.h>
49#include <unistd.h>
50#include <sys/socket.h>
51#include <stdlib.h>
52#include <netdb.h>
53#include <fcntl.h>
54#include <arpa/inet.h>
55#include <spawn.h>
56#include <ifaddrs.h>
57#include "inet.h"
58#include "capture.h"
59#include "support.h"
60#include "session.h"
61#include "ecn.h"
62#include "history.h"
63
64extern struct TcpSession session;
65
66void usage (char *name);
67int GetCannonicalInfo(char *string, u_int32_t *address);
68int BindTcpPort(int sockfd) ;
69
70void usage(char *name)
71{
72 printf("%s [options]\n", name);
73 printf("\t-n <target hostname | ipaddress>\n");
74 printf("\t-p <target port>\n");
75 printf("\t-m <mss>\n");
76 printf("\t-M <mtu>\n");
77 printf("\t-w <sourcePort>\n");
78 printf("\t-s <source hostname or ip address>\n");
79 printf("\t-f <file-name to get>\n");
80 printf("\t-d <interface name>\n");
fa34b6f5 81 printf("\t-C for CE path check\n");
755a8d69
A
82 printf("\t-S [A|R|X] SYN followed by ACK or RST or nothing\n");
83 printf("\t-F [set|clear|skip] how to handle firewall rules\n");
89c4ed63
A
84 return;
85}
86
87void SetupFirewall(u_int32_t targetIP, u_int16_t port, char *dev)
88{
89 char pfcmd[512];
90 char *pf_file_name = "/tmp/pf.conf";
755a8d69 91 int pf_fd = 0, rc;
89c4ed63 92 ssize_t bytes;
755a8d69 93 char *args[4];
89c4ed63
A
94
95 bzero(pfcmd, sizeof(pfcmd));
96
755a8d69 97 bzero(args, sizeof(args));
89c4ed63 98 sprintf(pfcmd, "block in quick on %s inet proto tcp from %s port %u\n",
755a8d69 99 dev, InetAddress(targetIP), port);
89c4ed63 100 if (session.debug >= SESSION_DEBUG_LOW)
755a8d69 101 printf("PF rule: %s\n", pfcmd);
89c4ed63
A
102
103 pf_fd = open(pf_file_name, O_RDWR|O_TRUNC|O_CREAT);
104 if (pf_fd < 0) {
105 perror("failed to open pf file");
106 exit(1);
107 }
108 bytes = write(pf_fd, pfcmd, strlen(pfcmd) + 1);
109 close(pf_fd);
755a8d69
A
110 args[0] = "pfctl";
111 args[1] = "-d";
112 args[2] = NULL;
113 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
114 if (rc != 0) {
115 printf("Failed to exec: pfctl -d: %d\n", rc);
116 Quit(FAIL);
117 }
118
119 args[1] = "-f";
120 args[2] = pf_file_name;
121 args[3] = NULL;
122 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
123 if (rc != 0) {
124 printf("Failed to exec: pfctl -f /tmp/pf.conf: %d\n", rc);
125 Quit(FAIL);
126 }
127
128 args[1] = "-e";
129 args[2] = NULL;
130 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
131 if (rc != 0) {
132 printf("Failed to exec: pfctl -e: %d\n", rc);
133 Quit(FAIL);
134 }
135}
136
137void CleanupFirewall()
138{
139 char * args[3];
140 int rc;
141
142 args[0] = "pfctl";
143 args[1] = "-d";
144 args[2] = NULL;
145 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
146 if (rc != 0) {
147 printf("Failed to exec: pfctl -d: %d\n", rc);
148 Quit(FAIL);
149 }
89c4ed63
A
150}
151
152void Cleanup()
153{
89c4ed63
A
154 if (session.initSession > 0) {
155 shutdown(session.socket, 2);
156 }
89c4ed63
A
157 if (session.initCapture > 0) {
158 CaptureEnd();
159 }
755a8d69
A
160 if (session.initFirewall > 0) {
161 CleanupFirewall();
162 }
89c4ed63
A
163}
164
165void Quit(int how)
166{
167 SendReset();
168 Cleanup();
169 fflush(stdout);
170 fflush(stderr);
171 exit(how);
172}
173
174void SigHandle(int signo)
175{
176 Cleanup();
177 fflush(stdout);
178 fflush(stderr);
179 exit(-1);
180}
181
182int GetCannonicalInfo(char *string, u_int32_t *address)
183{
184 struct hostent *hp;
185 /* Is string in dotted decimal format? */
186 if ((*address = inet_addr(string)) == INADDR_NONE) {
187 /* No, then lookup IP address */
188 if ((hp = gethostbyname(string)) == NULL) {
189 /* Can't find IP address */
190 printf("ERROR: Couldn't obtain address for %s\n"
191 "RETURN CODE: %d\n", string, FAIL);
192 return(-1);
193 } else {
194 strncpy(string, hp->h_name, MAXHOSTNAMELEN-1);
195 memcpy((void *)address, (void *)hp->h_addr,
196 hp->h_length);
197 }
198 } else {
199 if ((hp = gethostbyaddr((char *)address, sizeof(*address),
200 AF_INET)) == NULL) {
201 /*
202 * Can't get cannonical hostname, so just use
203 * input string
204 */
205 if (session.debug) {
206 printf("WARNING: Couldn't obtain cannonical"
207 " name for %s\nRETURN CODE: %d",
208 string, NO_SRC_CANON_INFO);
209 }
210 /* strncpy(name, string, MAXHOSTNAMELEN - 1);*/
211 } else {
212 /* strncpy(name, hp->h_name, MAXHOSTNAMELEN - 1);*/
213 }
214 }
215 return(0);
216}
217
218int BindTcpPort(int sockfd)
219{
220 struct sockaddr_in sockName;
221 int port, result;
222 int randomOffset;
223
224#define START_PORT (50*1024)
225#define END_PORT (0xFFFF)
226
227 /*
228 * Choose random offset to reduce likelihood of
229 * collision with last run
230 */
231 randomOffset = (int)(1000.0*drand48());
232
233 /* Try to find a free port in the range START_PORT+1..END_PORT */
234 port = START_PORT+randomOffset;
235 do {
236 ++port;
237 sockName.sin_addr.s_addr = INADDR_ANY;
238 sockName.sin_family = AF_INET;
755a8d69 239 sockName.sin_port = 0; //htons(port);
89c4ed63
A
240 result = bind(sockfd, (struct sockaddr *)&sockName,
241 sizeof(sockName));
242 } while ((result < 0) && (port < END_PORT));
243
755a8d69 244
89c4ed63
A
245 if (result < 0) {
246 /* No free ports */
247 perror("bind");
248 port = 0;
755a8d69
A
249 } else {
250 socklen_t len = sizeof(sockName);
251 result = getsockname(sockfd, (struct sockaddr *)&sockName, &len);
252 if (result < 0) {
253 perror("getsockname");
254 port = 0;
255 } else {
256 port = ntohs(sockName.sin_port);
257 }
258 }
89c4ed63
A
259 return port;
260
261}
262
755a8d69
A
263#define FIREWALL_DEFAULT 0
264#define FIREWALL_SET_ONLY 1
265#define FIREWALL_CLEAR_ONLY 2
266#define FIREWALL_SKIP 3
89c4ed63
A
267
268int main(int argc, char **argv)
269{
270 u_int32_t targetIpAddress = 0;
271 u_int16_t targetPort = DEFAULT_TARGETPORT;
272 u_int16_t sourcePort = 0;
273 u_int32_t sourceIpAddress = 0;
274 int mss = DEFAULT_MSS;
275 int mtu = DEFAULT_MTU;
fa34b6f5 276 int fd, opt, usedev = 0, rc = 0, path_check = 0;
755a8d69 277 int syn_test = 0, syn_reply = 0;
89c4ed63
A
278 struct sockaddr_in saddr;
279 char dev[11]; /* device name for pcap init */
280 struct ifaddrs *ifap, *tmp;
755a8d69 281 int firewall_mode = FIREWALL_DEFAULT;
89c4ed63
A
282
283 bzero(&session, sizeof(session));
755a8d69 284 while ((opt = getopt(argc, argv, "n:p:w:m:M:s:d:f:-CS:vF:")) != -1) {
89c4ed63 285 switch (opt) {
755a8d69
A
286 case 'n':
287 if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
288 printf("Target host name too long, max %u chars\n", MAXHOSTNAMELEN);
289 Quit(FAIL);
290 }
291 strncpy(session.targetHostName, optarg,
292 MAXHOSTNAMELEN);
293 strncpy(session.targetName, session.targetHostName,
294 MAXHOSTNAMELEN);
295 break;
296 case 'p':
297 targetPort = atoi(optarg);
298 break;
299 case 'm':
300 mss = atoi(optarg);
301 break;
302 case 'M':
303 mtu = atoi(optarg);
304 break;
305 case 'w':
306 sourcePort = atoi(optarg);
307 break;
308 case 's':
309 if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
310 printf("Source host name too long, max %u chars\n", MAXHOSTNAMELEN);
311 Quit(FAIL);
312 }
313 strncpy(session.sourceHostName, optarg,
314 MAXHOSTNAMELEN);
315 break;
316 case 'd':
317 if (strlen(optarg) > (sizeof(dev) - 1)) {
318 printf("Interface nae is too large, max %lu chars\n", (sizeof(dev) - 1));
319 Quit(FAIL);
320 }
321 bzero(dev, sizeof(dev));
322 strncpy(dev, optarg, (sizeof(dev) - 1));
323 usedev = 1;
324 break;
325 case 'f':
326 if (strlen(optarg) > 0) {
327 session.filename = strndup(optarg, strlen(optarg) + 1);
328 } else {
329 printf("Invalid file name \n");
330 }
331 break;
332 case 'F':
333 if (strcasecmp(optarg, "default") == 0)
334 firewall_mode = FIREWALL_DEFAULT;
335 else if (strcasecmp(optarg, "set") == 0)
336 firewall_mode = FIREWALL_SET_ONLY;
337 else if (strcasecmp(optarg, "clear") == 0)
338 firewall_mode = FIREWALL_CLEAR_ONLY;
339 else if (strcasecmp(optarg, "skip") == 0)
340 firewall_mode = FIREWALL_SKIP;
341 else
342 printf("firewall mode\n");
343 break;
344 case 'C':
345 path_check = 1;
346 break;
347 case 'S':
348 syn_test = 1;
349 if (strcasecmp(optarg, "A") == 0)
350 syn_reply = TCPFLAGS_ACK;
351 else if (strcasecmp(optarg, "R") == 0)
352 syn_reply = TCPFLAGS_RST;
353 else if (strcasecmp(optarg, "X") == 0)
354 syn_reply = 0;
355 else
356 printf("Invalid SYN reply \n");
357 break;
358 case 'v':
359 session.debug++;
360 break;
361 default:
362 usage(argv[0]);
363 exit(1);
89c4ed63
A
364 }
365 }
366 signal(SIGTERM, SigHandle);
367 signal(SIGINT, SigHandle);
368 signal(SIGHUP, SigHandle);
755a8d69 369
89c4ed63
A
370 if (GetCannonicalInfo(session.targetHostName, &targetIpAddress) < 0)
371 {
372 printf("Failed to convert targetIP address\n");
373 Quit(NO_TARGET_CANON_INFO);
755a8d69
A
374 }
375 /*
376 if (GetCannonicalInfo(session.sourceHostName, &sourceIpAddress) < 0)
377 {
89c4ed63
A
378 printf("Failed to convert source IP address\n");
379 Quit(NO_TARGET_CANON_INFO);
755a8d69
A
380 }
381 */
89c4ed63
A
382 rc = getifaddrs(&ifap);
383 if (rc != 0 || ifap == NULL) {
384 printf("Failed to get source addresswith getifaddrs: %d\n", rc);
385 Quit(FAIL);
386 }
387 tmp = ifap;
388 sourceIpAddress = 0;
389 bzero(session.sourceHostName, MAXHOSTNAMELEN);
390 for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
391 struct sockaddr_in *sin;
392 if (tmp->ifa_addr == NULL)
393 continue;
394 if (tmp->ifa_addr->sa_family != PF_INET)
395 continue;
396 if (usedev == 1) {
397 /* we know which interface to use */
398 if (strcmp(dev, tmp->ifa_name) == 0) {
399 sin = (struct sockaddr_in *)tmp->ifa_addr;
400 sourceIpAddress = sin->sin_addr.s_addr;
401 strncpy(session.sourceHostName,
755a8d69
A
402 inet_ntoa(sin->sin_addr),
403 MAXHOSTNAMELEN);
89c4ed63
A
404 } else {
405 continue;
406 }
407 } else {
408 /* pick the first address */
409 bzero(dev, sizeof(dev));
410 sin = (struct sockaddr_in *)tmp->ifa_addr;
411 sourceIpAddress = sin->sin_addr.s_addr;
412 strncpy(session.sourceHostName,
755a8d69
A
413 inet_ntoa(sin->sin_addr),
414 MAXHOSTNAMELEN);
415 strncpy(dev, tmp->ifa_name, sizeof(dev));
89c4ed63
A
416 }
417 }
418 freeifaddrs(ifap);
419 if (sourceIpAddress == 0) {
420 printf("Failed to get source Ip address\n");
421 Quit(FAIL);
422 }
423
424 if (sourcePort == 0) {
425 bzero(&saddr, sizeof(saddr));
426 saddr.sin_family = AF_INET;
427 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
428 printf("Can't open socket\n");
429 return (-1);
430 }
431 if ((sourcePort = BindTcpPort(fd)) == 0) {
432 printf("Can't bind to port\n");
433 return (-1);
434 }
435 }
89c4ed63
A
436 printf("Source: %s:%d\n", session.sourceHostName, sourcePort);
437 printf("Destination: %s:%d\n", session.targetHostName, targetPort);
438
755a8d69
A
439 switch (firewall_mode) {
440 case FIREWALL_DEFAULT:
441 SetupFirewall(targetIpAddress, targetPort, dev);
442 session.initFirewall = 1;
443 break;
444 case FIREWALL_SET_ONLY:
445 SetupFirewall(targetIpAddress, targetPort, dev);
446 goto done;
447 case FIREWALL_CLEAR_ONLY:
448 session.initFirewall = 1;
449 goto done;
450 case FIREWALL_SKIP:
451 break;
452 }
453
454 CaptureInit(sourceIpAddress, sourcePort, targetIpAddress,
455 targetPort, dev);
456 session.initCapture = 1;
457
89c4ed63
A
458
459 printf("Starting ECN test\n");
755a8d69
A
460 if (syn_test) {
461 session.dont_send_reset = 1;
462 SynTest(sourceIpAddress, sourcePort, targetIpAddress,
463 targetPort, mss, syn_reply);
464 } else if (path_check) {
465 ECNPathCheckTest(sourceIpAddress, sourcePort, targetIpAddress,
466 targetPort, mss);
fa34b6f5 467 } else {
755a8d69
A
468 ECNTest(sourceIpAddress, sourcePort, targetIpAddress,
469 targetPort, mss);
fa34b6f5 470 }
755a8d69 471done:
fa34b6f5 472 Quit(SUCCESS);
89c4ed63
A
473 close(session.socket);
474 return (0);
475}