1/* $FreeBSD$ */
2/*
3 * ipsend.c (C) 1995-1998 Darren Reed
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7#if !defined(lint)
8static const char sccsid[] = "@(#)ipsend.c	1.5 12/10/95 (C)1995 Darren Reed";
9static const char rcsid[] = "@(#)$Id$";
10#endif
11#include <sys/param.h>
12#include <sys/types.h>
13#include <sys/time.h>
14#include <sys/socket.h>
15#include <netinet/in.h>
16#include <arpa/inet.h>
17#include <netinet/in_systm.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <netdb.h>
22#include <string.h>
23#include <netinet/ip.h>
24#ifndef	linux
25# include <netinet/ip_var.h>
26#endif
27#include "ipsend.h"
28#include "ipf.h"
29#ifndef	linux
30# include <netinet/udp_var.h>
31#endif
32
33
34extern	char	*optarg;
35extern	int	optind;
36extern	void	iplang __P((FILE *));
37
38char	options[68];
39int	opts;
40#ifdef linux
41char	default_device[] = "eth0";
42#else
43# ifdef ultrix
44char	default_device[] = "ln0";
45# else
46#  ifdef __bsdi__
47char	default_device[] = "ef0";
48#  else
49#   ifdef __sgi
50char	default_device[] = "ec0";
51#   else
52#    ifdef __hpux
53char	default_device[] = "lan0";
54#    else
55char	default_device[] = "le0";
56#    endif /* __hpux */
57#   endif /* __sgi */
58#  endif /* __bsdi__ */
59# endif /* ultrix */
60#endif /* linux */
61
62
63static	void	usage __P((char *));
64static	void	do_icmp __P((ip_t *, char *));
65void udpcksum(ip_t *, struct udphdr *, int);
66int	main __P((int, char **));
67
68
69static	void	usage(prog)
70	char	*prog;
71{
72	fprintf(stderr, "Usage: %s [options] dest [flags]\n\
73\toptions:\n\
74\t\t-d\tdebug mode\n\
75\t\t-i device\tSend out on this device\n\
76\t\t-f fragflags\tcan set IP_MF or IP_DF\n\
77\t\t-g gateway\tIP gateway to use if non-local dest.\n\
78\t\t-I code,type[,gw[,dst[,src]]]\tSet ICMP protocol\n\
79\t\t-m mtu\t\tfake MTU to use when sending out\n\
80\t\t-P protocol\tSet protocol by name\n\
81\t\t-s src\t\tsource address for IP packet\n\
82\t\t-T\t\tSet TCP protocol\n\
83\t\t-t port\t\tdestination port\n\
84\t\t-U\t\tSet UDP protocol\n\
85\t\t-v\tverbose mode\n\
86\t\t-w <window>\tSet the TCP window size\n\
87", prog);
88	fprintf(stderr, "Usage: %s [-dv] -L <filename>\n\
89\toptions:\n\
90\t\t-d\tdebug mode\n\
91\t\t-L filename\tUse IP language for sending packets\n\
92\t\t-v\tverbose mode\n\
93", prog);
94	exit(1);
95}
96
97
98static void do_icmp(ip, args)
99	ip_t *ip;
100	char *args;
101{
102	struct	icmp	*ic;
103	char	*s;
104
105	ip->ip_p = IPPROTO_ICMP;
106	ip->ip_len += sizeof(*ic);
107	ic = (struct icmp *)(ip + 1);
108	bzero((char *)ic, sizeof(*ic));
109	if (!(s = strchr(args, ',')))
110	    {
111		fprintf(stderr, "ICMP args missing: ,\n");
112		return;
113	    }
114	*s++ = '\0';
115	ic->icmp_type = atoi(args);
116	ic->icmp_code = atoi(s);
117	if (ic->icmp_type == ICMP_REDIRECT && strchr(s, ','))
118	    {
119		char	*t;
120
121		t = strtok(s, ",");
122		t = strtok(NULL, ",");
123		if (resolve(t, (char *)&ic->icmp_gwaddr) == -1)
124		    {
125			fprintf(stderr,"Cant resolve %s\n", t);
126			exit(2);
127		    }
128		if ((t = strtok(NULL, ",")))
129		    {
130			if (resolve(t, (char *)&ic->icmp_ip.ip_dst) == -1)
131			    {
132				fprintf(stderr,"Cant resolve %s\n", t);
133				exit(2);
134			    }
135			if ((t = strtok(NULL, ",")))
136			    {
137				if (resolve(t,
138					    (char *)&ic->icmp_ip.ip_src) == -1)
139				    {
140					fprintf(stderr,"Cant resolve %s\n", t);
141					exit(2);
142				    }
143			    }
144		    }
145	    }
146}
147
148
149int send_packets(dev, mtu, ip, gwip)
150	char *dev;
151	int mtu;
152	ip_t *ip;
153	struct in_addr gwip;
154{
155	int wfd;
156
157	wfd = initdevice(dev, 5);
158	if (wfd == -1)
159		return -1;
160	return send_packet(wfd, mtu, ip, gwip);
161}
162
163void
164udpcksum(ip_t *ip, struct udphdr *udp, int len)
165{
166	union pseudoh {
167		struct hdr {
168			u_short len;
169			u_char ttl;
170			u_char proto;
171			u_32_t src;
172			u_32_t dst;
173		} h;
174		u_short w[6];
175	} ph;
176	u_32_t temp32;
177	u_short *opts;
178
179	ph.h.len = htons(len);
180	ph.h.ttl = 0;
181	ph.h.proto = IPPROTO_UDP;
182	ph.h.src = ip->ip_src.s_addr;
183	ph.h.dst = ip->ip_dst.s_addr;
184	temp32 = 0;
185	opts = &ph.w[0];
186	temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
187	temp32 = (temp32 >> 16) + (temp32 & 65535);
188	temp32 += (temp32 >> 16);
189	udp->uh_sum = temp32 & 65535;
190	udp->uh_sum = chksum((u_short *)udp, len);
191	if (udp->uh_sum == 0)
192		udp->uh_sum = 0xffff;
193}
194
195int main(argc, argv)
196	int	argc;
197	char	**argv;
198{
199	FILE	*langfile = NULL;
200	struct	in_addr	gwip;
201	tcphdr_t	*tcp;
202	udphdr_t	*udp;
203	ip_t	*ip;
204	char	*name =  argv[0], host[MAXHOSTNAMELEN + 1];
205	char	*gateway = NULL, *dev = NULL;
206	char	*src = NULL, *dst, *s;
207	int	mtu = 1500, olen = 0, c, nonl = 0;
208
209	/*
210	 * 65535 is maximum packet size...you never know...
211	 */
212	ip = (ip_t *)calloc(1, 65536);
213	tcp = (tcphdr_t *)(ip + 1);
214	udp = (udphdr_t *)tcp;
215	ip->ip_len = sizeof(*ip);
216	IP_HL_A(ip, sizeof(*ip) >> 2);
217
218	while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) {
219		switch (c)
220		{
221		case 'I' :
222			nonl++;
223			if (ip->ip_p)
224			    {
225				fprintf(stderr, "Protocol already set: %d\n",
226					ip->ip_p);
227				break;
228			    }
229			do_icmp(ip, optarg);
230			break;
231		case 'L' :
232			if (nonl) {
233				fprintf(stderr,
234					"Incorrect usage of -L option.\n");
235				usage(name);
236			}
237			if (!strcmp(optarg, "-"))
238				langfile = stdin;
239			else if (!(langfile = fopen(optarg, "r"))) {
240				fprintf(stderr, "can't open file %s\n",
241					optarg);
242				exit(1);
243			}
244			iplang(langfile);
245			return 0;
246		case 'P' :
247		    {
248			struct	protoent	*p;
249
250			nonl++;
251			if (ip->ip_p)
252			    {
253				fprintf(stderr, "Protocol already set: %d\n",
254					ip->ip_p);
255				break;
256			    }
257			if ((p = getprotobyname(optarg)))
258				ip->ip_p = p->p_proto;
259			else
260				fprintf(stderr, "Unknown protocol: %s\n",
261					optarg);
262			break;
263		    }
264		case 'T' :
265			nonl++;
266			if (ip->ip_p)
267			    {
268				fprintf(stderr, "Protocol already set: %d\n",
269					ip->ip_p);
270				break;
271			    }
272			ip->ip_p = IPPROTO_TCP;
273			ip->ip_len += sizeof(tcphdr_t);
274			break;
275		case 'U' :
276			nonl++;
277			if (ip->ip_p)
278			    {
279				fprintf(stderr, "Protocol already set: %d\n",
280					ip->ip_p);
281				break;
282			    }
283			ip->ip_p = IPPROTO_UDP;
284			ip->ip_len += sizeof(udphdr_t);
285			break;
286		case 'd' :
287			opts |= OPT_DEBUG;
288			break;
289		case 'f' :
290			nonl++;
291			ip->ip_off = strtol(optarg, NULL, 0);
292			break;
293		case 'g' :
294			nonl++;
295			gateway = optarg;
296			break;
297		case 'i' :
298			nonl++;
299			dev = optarg;
300			break;
301		case 'm' :
302			nonl++;
303			mtu = atoi(optarg);
304			if (mtu < 28)
305			    {
306				fprintf(stderr, "mtu must be > 28\n");
307				exit(1);
308			    }
309			break;
310		case 'o' :
311			nonl++;
312			olen = buildopts(optarg, options, (IP_HL(ip) - 5) << 2);
313			break;
314		case 's' :
315			nonl++;
316			src = optarg;
317			break;
318		case 't' :
319			nonl++;
320			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
321				tcp->th_dport = htons(atoi(optarg));
322			break;
323		case 'v' :
324			opts |= OPT_VERBOSE;
325			break;
326		case 'w' :
327			nonl++;
328			if (ip->ip_p == IPPROTO_TCP)
329				tcp->th_win = atoi(optarg);
330			else
331				fprintf(stderr, "set protocol to TCP first\n");
332			break;
333		default :
334			fprintf(stderr, "Unknown option \"%c\"\n", c);
335			usage(name);
336		}
337	}
338
339	if (argc - optind < 1)
340		usage(name);
341	dst = argv[optind++];
342
343	if (!src)
344	    {
345		gethostname(host, sizeof(host));
346		src = host;
347	    }
348
349	if (resolve(src, (char *)&ip->ip_src) == -1)
350	    {
351		fprintf(stderr,"Cant resolve %s\n", src);
352		exit(2);
353	    }
354
355	if (resolve(dst, (char *)&ip->ip_dst) == -1)
356	    {
357		fprintf(stderr,"Cant resolve %s\n", dst);
358		exit(2);
359	    }
360
361	if (!gateway)
362		gwip = ip->ip_dst;
363	else if (resolve(gateway, (char *)&gwip) == -1)
364	    {
365		fprintf(stderr,"Cant resolve %s\n", gateway);
366		exit(2);
367	    }
368
369	if (olen)
370	    {
371		int hlen;
372		char *p;
373
374		printf("Options: %d\n", olen);
375		hlen = sizeof(*ip) + olen;
376		IP_HL_A(ip, hlen >> 2);
377		ip->ip_len += olen;
378		p = (char *)malloc(65536);
379		if (p == NULL)
380		    {
381			fprintf(stderr, "malloc failed\n");
382			exit(2);
383		    }
384
385		bcopy(ip, p, sizeof(*ip));
386		bcopy(options, p + sizeof(*ip), olen);
387		bcopy(ip + 1, p + hlen, ip->ip_len - hlen);
388		ip = (ip_t *)p;
389
390		if (ip->ip_p == IPPROTO_TCP) {
391			tcp = (tcphdr_t *)(p + hlen);
392		} else if (ip->ip_p == IPPROTO_UDP) {
393			udp = (udphdr_t *)(p + hlen);
394		}
395	    }
396
397	if (ip->ip_p == IPPROTO_TCP)
398		for (s = argv[optind]; s && (c = *s); s++)
399			switch(c)
400			{
401			case 'S' : case 's' :
402				tcp->th_flags |= TH_SYN;
403				break;
404			case 'A' : case 'a' :
405				tcp->th_flags |= TH_ACK;
406				break;
407			case 'F' : case 'f' :
408				tcp->th_flags |= TH_FIN;
409				break;
410			case 'R' : case 'r' :
411				tcp->th_flags |= TH_RST;
412				break;
413			case 'P' : case 'p' :
414				tcp->th_flags |= TH_PUSH;
415				break;
416			case 'U' : case 'u' :
417				tcp->th_flags |= TH_URG;
418				break;
419			}
420
421	if (!dev)
422		dev = default_device;
423	printf("Device:  %s\n", dev);
424	printf("Source:  %s\n", inet_ntoa(ip->ip_src));
425	printf("Dest:    %s\n", inet_ntoa(ip->ip_dst));
426	printf("Gateway: %s\n", inet_ntoa(gwip));
427	if (ip->ip_p == IPPROTO_TCP && tcp->th_flags)
428		printf("Flags:   %#x\n", tcp->th_flags);
429	printf("mtu:     %d\n", mtu);
430
431	if (ip->ip_p == IPPROTO_UDP) {
432		udp->uh_sum = 0;
433		udpcksum(ip, udp, ip->ip_len - (IP_HL(ip) << 2));
434	}
435#ifdef	DOSOCKET
436	if (ip->ip_p == IPPROTO_TCP && tcp->th_dport)
437		return do_socket(dev, mtu, ip, gwip);
438#endif
439	return send_packets(dev, mtu, ip, gwip);
440}
441