3 International Computer Science Institute
6 This file may contain software code originally developed for the
7 Sting project. The Sting software carries the following copyright:
9 Copyright (c) 1998, 1999
10 Stefan Savage and the University of Washington.
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
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.
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
44 #include <sys/types.h>
45 #include <sys/param.h>
50 #include <sys/socket.h>
54 #include <arpa/inet.h>
64 extern struct TcpSession session
;
66 void usage (char *name
);
67 int GetCannonicalInfo(char *string
, size_t str_size
, u_int32_t
*address
);
68 int BindTcpPort(int sockfd
) ;
70 void usage(char *name
)
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 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");
87 void SetupFirewall(u_int32_t targetIP
, u_int16_t port
, char *dev
)
90 char *pf_file_name
= "/tmp/pf.conf";
95 bzero(pfcmd
, sizeof(pfcmd
));
97 bzero(args
, sizeof(args
));
98 sprintf(pfcmd
, "block in quick on %s inet proto tcp from %s port %u\n",
99 dev
, InetAddress(targetIP
), port
);
100 if (session
.debug
>= SESSION_DEBUG_LOW
)
101 printf("PF rule: %s\n", pfcmd
);
103 pf_fd
= open(pf_file_name
, O_RDWR
|O_TRUNC
|O_CREAT
);
105 perror("failed to open pf file");
108 bytes
= write(pf_fd
, pfcmd
, strlen(pfcmd
) + 1);
113 rc
= posix_spawn(NULL
, "/sbin/pfctl", NULL
, NULL
, args
, NULL
);
115 printf("Failed to exec: pfctl -d: %d\n", rc
);
120 args
[2] = pf_file_name
;
122 rc
= posix_spawn(NULL
, "/sbin/pfctl", NULL
, NULL
, args
, NULL
);
124 printf("Failed to exec: pfctl -f /tmp/pf.conf: %d\n", rc
);
130 rc
= posix_spawn(NULL
, "/sbin/pfctl", NULL
, NULL
, args
, NULL
);
132 printf("Failed to exec: pfctl -e: %d\n", rc
);
137 void CleanupFirewall()
145 rc
= posix_spawn(NULL
, "/sbin/pfctl", NULL
, NULL
, args
, NULL
);
147 printf("Failed to exec: pfctl -d: %d\n", rc
);
154 if (session
.initSession
> 0) {
155 shutdown(session
.socket
, 2);
157 if (session
.initCapture
> 0) {
160 if (session
.initFirewall
> 0) {
174 void SigHandle(int signo
)
182 int GetCannonicalInfo(char *string
, size_t str_size
, u_int32_t
*address
)
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
);
194 strlcpy(string
, hp
->h_name
, str_size
);
195 memcpy((void *)address
, (void *)hp
->h_addr
,
199 if ((hp
= gethostbyaddr((char *)address
, sizeof(*address
),
202 * Can't get cannonical hostname, so just use
206 printf("WARNING: Couldn't obtain cannonical"
207 " name for %s\nRETURN CODE: %d",
208 string
, NO_SRC_CANON_INFO
);
210 /* strlcpy(name, string, MAXHOSTNAMELEN);*/
212 /* strlcpy(name, hp->h_name, MAXHOSTNAMELEN);*/
218 int BindTcpPort(int sockfd
)
220 struct sockaddr_in sockName
;
224 #define START_PORT (50*1024)
225 #define END_PORT (0xFFFF)
228 * Choose random offset to reduce likelihood of
229 * collision with last run
231 randomOffset
= (int)(1000.0*drand48());
233 /* Try to find a free port in the range START_PORT+1..END_PORT */
234 port
= START_PORT
+randomOffset
;
237 sockName
.sin_addr
.s_addr
= INADDR_ANY
;
238 sockName
.sin_family
= AF_INET
;
239 sockName
.sin_port
= 0; //htons(port);
240 result
= bind(sockfd
, (struct sockaddr
*)&sockName
,
242 } while ((result
< 0) && (port
< END_PORT
));
250 socklen_t len
= sizeof(sockName
);
251 result
= getsockname(sockfd
, (struct sockaddr
*)&sockName
, &len
);
253 perror("getsockname");
256 port
= ntohs(sockName
.sin_port
);
263 #define FIREWALL_DEFAULT 0
264 #define FIREWALL_SET_ONLY 1
265 #define FIREWALL_CLEAR_ONLY 2
266 #define FIREWALL_SKIP 3
268 int main(int argc
, char **argv
)
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
;
276 int fd
, opt
, usedev
= 0, rc
= 0, path_check
= 0;
277 int syn_test
= 0, syn_reply
= 0;
278 struct sockaddr_in saddr
;
279 char dev
[11]; /* device name for pcap init */
280 struct ifaddrs
*ifap
, *tmp
;
281 int firewall_mode
= FIREWALL_DEFAULT
;
283 bzero(&session
, sizeof(session
));
284 while ((opt
= getopt(argc
, argv
, "n:p:w:m:M:s:d:f:-CS:vF:")) != -1) {
287 if (strlen(optarg
) > (MAXHOSTNAMELEN
- 1)) {
288 printf("Target host name too long, max %u chars\n", MAXHOSTNAMELEN
);
291 strlcpy(session
.targetHostName
, optarg
,
292 sizeof(session
.targetHostName
));
293 strlcpy(session
.targetName
, session
.targetHostName
,
294 sizeof(session
.targetName
));
297 targetPort
= atoi(optarg
);
306 sourcePort
= atoi(optarg
);
309 if (strlen(optarg
) > (MAXHOSTNAMELEN
- 1)) {
310 printf("Source host name too long, max %u chars\n", MAXHOSTNAMELEN
);
313 strlcpy(session
.sourceHostName
, optarg
,
317 if (strlen(optarg
) > (sizeof(dev
) - 1)) {
318 printf("Interface nae is too large, max %lu chars\n", (sizeof(dev
) - 1));
321 bzero(dev
, sizeof(dev
));
322 strlcpy(dev
, optarg
, sizeof(dev
));
326 if (strlen(optarg
) > 0) {
327 session
.filename
= strndup(optarg
, strlen(optarg
) + 1);
329 printf("Invalid file name \n");
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
;
342 printf("firewall mode\n");
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)
356 printf("Invalid SYN reply \n");
366 signal(SIGTERM
, SigHandle
);
367 signal(SIGINT
, SigHandle
);
368 signal(SIGHUP
, SigHandle
);
370 if (GetCannonicalInfo(session
.targetHostName
, sizeof(session
.targetHostName
),
371 &targetIpAddress
) < 0)
373 printf("Failed to convert targetIP address\n");
374 Quit(NO_TARGET_CANON_INFO
);
376 rc
= getifaddrs(&ifap
);
377 if (rc
!= 0 || ifap
== NULL
) {
378 printf("Failed to get source addresswith getifaddrs: %d\n", rc
);
383 bzero(session
.sourceHostName
, MAXHOSTNAMELEN
);
384 for (tmp
= ifap
; tmp
!= NULL
; tmp
= tmp
->ifa_next
) {
385 struct sockaddr_in
*sin
;
386 if (tmp
->ifa_addr
== NULL
)
388 if (tmp
->ifa_addr
->sa_family
!= PF_INET
)
391 /* we know which interface to use */
392 if (strcmp(dev
, tmp
->ifa_name
) == 0) {
393 sin
= (struct sockaddr_in
*)tmp
->ifa_addr
;
394 sourceIpAddress
= sin
->sin_addr
.s_addr
;
395 strlcpy(session
.sourceHostName
,
396 inet_ntoa(sin
->sin_addr
),
397 sizeof(session
.sourceHostName
));
402 /* pick the first address */
403 bzero(dev
, sizeof(dev
));
404 sin
= (struct sockaddr_in
*)tmp
->ifa_addr
;
405 sourceIpAddress
= sin
->sin_addr
.s_addr
;
406 strlcpy(session
.sourceHostName
,
407 inet_ntoa(sin
->sin_addr
),
408 sizeof(session
.sourceHostName
));
409 strlcpy(dev
, tmp
->ifa_name
, sizeof(dev
));
413 if (sourceIpAddress
== 0) {
414 printf("Failed to get source Ip address\n");
418 if (sourcePort
== 0) {
419 bzero(&saddr
, sizeof(saddr
));
420 saddr
.sin_family
= AF_INET
;
421 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
422 printf("Can't open socket\n");
425 if ((sourcePort
= BindTcpPort(fd
)) == 0) {
426 printf("Can't bind to port\n");
430 printf("Source: %s:%d\n", session
.sourceHostName
, sourcePort
);
431 printf("Destination: %s:%d\n", session
.targetHostName
, targetPort
);
433 switch (firewall_mode
) {
434 case FIREWALL_DEFAULT
:
435 SetupFirewall(targetIpAddress
, targetPort
, dev
);
436 session
.initFirewall
= 1;
438 case FIREWALL_SET_ONLY
:
439 SetupFirewall(targetIpAddress
, targetPort
, dev
);
441 case FIREWALL_CLEAR_ONLY
:
442 session
.initFirewall
= 1;
448 CaptureInit(sourceIpAddress
, sourcePort
, targetIpAddress
,
450 session
.initCapture
= 1;
453 printf("Starting ECN test\n");
455 session
.dont_send_reset
= 1;
456 SynTest(sourceIpAddress
, sourcePort
, targetIpAddress
,
457 targetPort
, mss
, syn_reply
);
458 } else if (path_check
) {
459 ECNPathCheckTest(sourceIpAddress
, sourcePort
, targetIpAddress
,
462 ECNTest(sourceIpAddress
, sourcePort
, targetIpAddress
,
467 close(session
.socket
);