]> git.saurik.com Git - apple/network_cmds.git/blame_incremental - ecnprobe/ecn_probe.c
network_cmds-511.tar.gz
[apple/network_cmds.git] / ecnprobe / ecn_probe.c
... / ...
CommitLineData
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");
81 printf("\t-C for CE path check\n");
82 return;
83}
84
85void SetupFirewall(u_int32_t targetIP, u_int16_t port, char *dev)
86{
87 char pfcmd[512];
88 char *pf_file_name = "/tmp/pf.conf";
89 int pf_fd = 0, rc;
90 ssize_t bytes;
91 char *args[4];
92
93 bzero(pfcmd, sizeof(pfcmd));
94
95 bzero(args, sizeof(args));
96 sprintf(pfcmd, "block in quick on %s inet proto tcp from %s port %u\n",
97 dev, InetAddress(targetIP), port);
98 if (session.debug >= SESSION_DEBUG_LOW)
99 printf("PF rule: %s\n", pfcmd);
100
101 pf_fd = open(pf_file_name, O_RDWR|O_TRUNC|O_CREAT);
102 if (pf_fd < 0) {
103 perror("failed to open pf file");
104 exit(1);
105 }
106 bytes = write(pf_fd, pfcmd, strlen(pfcmd) + 1);
107 close(pf_fd);
108 args[0] = "pfctl";
109 args[1] = "-d";
110 args[2] = NULL;
111 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
112 if (rc != 0) {
113 printf("Failed to exec: pfctl -d: %d\n", rc);
114 Quit(FAIL);
115 }
116
117 args[1] = "-f";
118 args[2] = pf_file_name;
119 args[3] = NULL;
120 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
121 if (rc != 0) {
122 printf("Failed to exec: pfctl -f /tmp/pf.conf: %d\n", rc);
123 Quit(FAIL);
124 }
125
126 args[1] = "-e";
127 args[2] = NULL;
128 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
129 if (rc != 0) {
130 printf("Failed to exec: pfctl -e: %d\n", rc);
131 Quit(FAIL);
132 }
133}
134
135void Cleanup()
136{
137 char * args[3];
138 int rc;
139 if (session.initSession > 0) {
140 shutdown(session.socket, 2);
141 }
142
143 if (session.initCapture > 0) {
144 CaptureEnd();
145 }
146 args[0] = "pfctl";
147 args[1] = "-d";
148 args[2] = NULL;
149 rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
150 if (rc != 0) {
151 printf("Failed to exec: pfctl -d: %d\n", rc);
152 Quit(FAIL);
153 }
154}
155
156void Quit(int how)
157{
158 SendReset();
159 Cleanup();
160 fflush(stdout);
161 fflush(stderr);
162 exit(how);
163}
164
165void SigHandle(int signo)
166{
167 Cleanup();
168 fflush(stdout);
169 fflush(stderr);
170 exit(-1);
171}
172
173int GetCannonicalInfo(char *string, u_int32_t *address)
174{
175 struct hostent *hp;
176 /* Is string in dotted decimal format? */
177 if ((*address = inet_addr(string)) == INADDR_NONE) {
178 /* No, then lookup IP address */
179 if ((hp = gethostbyname(string)) == NULL) {
180 /* Can't find IP address */
181 printf("ERROR: Couldn't obtain address for %s\n"
182 "RETURN CODE: %d\n", string, FAIL);
183 return(-1);
184 } else {
185 strncpy(string, hp->h_name, MAXHOSTNAMELEN-1);
186 memcpy((void *)address, (void *)hp->h_addr,
187 hp->h_length);
188 }
189 } else {
190 if ((hp = gethostbyaddr((char *)address, sizeof(*address),
191 AF_INET)) == NULL) {
192 /*
193 * Can't get cannonical hostname, so just use
194 * input string
195 */
196 if (session.debug) {
197 printf("WARNING: Couldn't obtain cannonical"
198 " name for %s\nRETURN CODE: %d",
199 string, NO_SRC_CANON_INFO);
200 }
201 /* strncpy(name, string, MAXHOSTNAMELEN - 1);*/
202 } else {
203 /* strncpy(name, hp->h_name, MAXHOSTNAMELEN - 1);*/
204 }
205 }
206 return(0);
207}
208
209int BindTcpPort(int sockfd)
210{
211 struct sockaddr_in sockName;
212 int port, result;
213 int randomOffset;
214
215#define START_PORT (50*1024)
216#define END_PORT (0xFFFF)
217
218 /*
219 * Choose random offset to reduce likelihood of
220 * collision with last run
221 */
222 randomOffset = (int)(1000.0*drand48());
223
224 /* Try to find a free port in the range START_PORT+1..END_PORT */
225 port = START_PORT+randomOffset;
226 do {
227 ++port;
228 sockName.sin_addr.s_addr = INADDR_ANY;
229 sockName.sin_family = AF_INET;
230 sockName.sin_port = htons(port);
231 result = bind(sockfd, (struct sockaddr *)&sockName,
232 sizeof(sockName));
233 } while ((result < 0) && (port < END_PORT));
234
235 if (result < 0) {
236 /* No free ports */
237 perror("bind");
238 port = 0;
239 }
240 return port;
241
242}
243
244
245
246int main(int argc, char **argv)
247{
248 u_int32_t targetIpAddress = 0;
249 u_int16_t targetPort = DEFAULT_TARGETPORT;
250 u_int16_t sourcePort = 0;
251 u_int32_t sourceIpAddress = 0;
252 int mss = DEFAULT_MSS;
253 int mtu = DEFAULT_MTU;
254 int fd, opt, usedev = 0, rc = 0, path_check = 0;
255 struct sockaddr_in saddr;
256 char dev[11]; /* device name for pcap init */
257 struct ifaddrs *ifap, *tmp;
258
259 bzero(&session, sizeof(session));
260 while ((opt = getopt(argc, argv, "n:p:w:m:M:s:d:f:-C")) != -1) {
261 switch (opt) {
262 case 'n':
263 if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
264 printf("Target host name too long, max %u chars\n", MAXHOSTNAMELEN);
265 Quit(FAIL);
266 }
267 strncpy(session.targetHostName, optarg,
268 MAXHOSTNAMELEN);
269 strncpy(session.targetName, session.targetHostName,
270 MAXHOSTNAMELEN);
271 break;
272 case 'p':
273 targetPort = atoi(optarg);
274 break;
275 case 'm':
276 mss = atoi(optarg);
277 break;
278 case 'M':
279 mtu = atoi(optarg);
280 break;
281 case 'w':
282 sourcePort = atoi(optarg);
283 break;
284 case 's':
285 if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
286 printf("Source host name too long, max %u chars\n", MAXHOSTNAMELEN);
287 Quit(FAIL);
288 }
289 strncpy(session.sourceHostName, optarg,
290 MAXHOSTNAMELEN);
291 break;
292 case 'd':
293 if (strlen(optarg) > (sizeof(dev) - 1)) {
294 printf("Interface nae is too large, max %lu chars\n", (sizeof(dev) - 1));
295 Quit(FAIL);
296 }
297 bzero(dev, sizeof(dev));
298 strncpy(dev, optarg, (sizeof(dev) - 1));
299 usedev = 1;
300 break;
301 case 'f':
302 if (strlen(optarg) > 0) {
303 session.filename = strndup(optarg, strlen(optarg) + 1);
304 } else {
305 printf("Invalid file name \n");
306 }
307 break;
308 case 'C':
309 path_check = 1;
310 break;
311 default:
312 usage(argv[0]);
313 exit(1);
314 }
315 }
316 signal(SIGTERM, SigHandle);
317 signal(SIGINT, SigHandle);
318 signal(SIGHUP, SigHandle);
319
320 if (GetCannonicalInfo(session.targetHostName, &targetIpAddress) < 0)
321 {
322 printf("Failed to convert targetIP address\n");
323 Quit(NO_TARGET_CANON_INFO);
324 }
325/*
326 if (GetCannonicalInfo(session.sourceHostName, &sourceIpAddress) < 0)
327 {
328 printf("Failed to convert source IP address\n");
329 Quit(NO_TARGET_CANON_INFO);
330 }
331*/
332 rc = getifaddrs(&ifap);
333 if (rc != 0 || ifap == NULL) {
334 printf("Failed to get source addresswith getifaddrs: %d\n", rc);
335 Quit(FAIL);
336 }
337 tmp = ifap;
338 sourceIpAddress = 0;
339 bzero(session.sourceHostName, MAXHOSTNAMELEN);
340 for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
341 struct sockaddr_in *sin;
342 if (tmp->ifa_addr == NULL)
343 continue;
344 if (tmp->ifa_addr->sa_family != PF_INET)
345 continue;
346 if (usedev == 1) {
347 /* we know which interface to use */
348 if (strcmp(dev, tmp->ifa_name) == 0) {
349 sin = (struct sockaddr_in *)tmp->ifa_addr;
350 sourceIpAddress = sin->sin_addr.s_addr;
351 strncpy(session.sourceHostName,
352 inet_ntoa(sin->sin_addr),
353 MAXHOSTNAMELEN);
354 } else {
355 continue;
356 }
357 } else {
358 /* pick the first address */
359 bzero(dev, sizeof(dev));
360 sin = (struct sockaddr_in *)tmp->ifa_addr;
361 sourceIpAddress = sin->sin_addr.s_addr;
362 strncpy(session.sourceHostName,
363 inet_ntoa(sin->sin_addr),
364 MAXHOSTNAMELEN);
365 strncpy(dev, tmp->ifa_name, sizeof(dev));
366 }
367 }
368 freeifaddrs(ifap);
369 if (sourceIpAddress == 0) {
370 printf("Failed to get source Ip address\n");
371 Quit(FAIL);
372 }
373
374 if (sourcePort == 0) {
375 bzero(&saddr, sizeof(saddr));
376 saddr.sin_family = AF_INET;
377 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
378 printf("Can't open socket\n");
379 return (-1);
380 }
381 if ((sourcePort = BindTcpPort(fd)) == 0) {
382 printf("Can't bind to port\n");
383 return (-1);
384 }
385 }
386 CaptureInit(sourceIpAddress, sourcePort, targetIpAddress,
387 targetPort, dev);
388 session.initCapture = 1;
389
390 printf("Source: %s:%d\n", session.sourceHostName, sourcePort);
391 printf("Destination: %s:%d\n", session.targetHostName, targetPort);
392
393 SetupFirewall(targetIpAddress, targetPort, dev);
394
395 printf("Starting ECN test\n");
396 if (path_check) {
397 ECNPathCheckTest(sourceIpAddress, sourcePort, targetIpAddress,
398 targetPort, mss);
399 } else {
400 ECNTest(sourceIpAddress, sourcePort, targetIpAddress,
401 targetPort, mss);
402 }
403 Quit(SUCCESS);
404 close(session.socket);
405 return (0);
406}