ip.c revision 92686
154359Sroberto/*
2132451Sroberto * ip.c (C) 1995-1998 Darren Reed
354359Sroberto *
454359Sroberto * See the IPFILTER.LICENCE file for details on licencing.
554359Sroberto */
654359Sroberto#ifdef __sgi
754359Sroberto# include <sys/ptimers.h>
854359Sroberto#endif
954359Sroberto#include <errno.h>
1054359Sroberto#include <stdio.h>
1154359Sroberto#include <stdlib.h>
1254359Sroberto#include <unistd.h>
13285612Sdelphij#include <string.h>
1454359Sroberto#include <sys/types.h>
15285612Sdelphij#include <netinet/in_systm.h>
1654359Sroberto#include <sys/socket.h>
1754359Sroberto#include <net/if.h>
1854359Sroberto#include <netinet/in.h>
19132451Sroberto#include <netinet/ip.h>
2054359Sroberto#include <netinet/tcp.h>
21132451Sroberto#include <netinet/udp.h>
2254359Sroberto#include <netinet/ip_icmp.h>
2354359Sroberto#include <sys/param.h>
2454359Sroberto#ifndef	linux
2554359Sroberto# include <netinet/if_ether.h>
2654359Sroberto# include <netinet/ip_var.h>
27132451Sroberto# if __FreeBSD_version >= 300000
28132451Sroberto#  include <net/if_var.h>
29132451Sroberto# endif
30132451Sroberto#endif
31132451Sroberto#include "ipsend.h"
32132451Sroberto
3354359Sroberto#if !defined(lint)
3454359Srobertostatic const char sccsid[] = "%W% %G% (C)1995";
35132451Srobertostatic const char rcsid[] = "@(#)$Id: ip.c,v 2.1.4.4 2002/02/22 15:32:57 darrenr Exp $";
36132451Sroberto#endif
37132451Sroberto
38132451Srobertostatic	char	*ipbuf = NULL, *ethbuf = NULL;
39132451Sroberto
4054359Sroberto
41132451Srobertou_short	chksum(buf,len)
42132451Srobertou_short	*buf;
43132451Srobertoint	len;
44132451Sroberto{
45132451Sroberto	u_long	sum = 0;
46285612Sdelphij	int	nwords = len >> 1;
47285612Sdelphij
48285612Sdelphij	for(; nwords > 0; nwords--)
49285612Sdelphij		sum += *buf++;
50285612Sdelphij	sum = (sum>>16) + (sum & 0xffff);
51285612Sdelphij	sum += (sum >>16);
52285612Sdelphij	return (~sum);
53132451Sroberto}
5454359Sroberto
5554359Sroberto
56285612Sdelphijint	send_ether(nfd, buf, len, gwip)
57285612Sdelphijint	nfd, len;
58285612Sdelphijchar	*buf;
5954359Srobertostruct	in_addr	gwip;
60285612Sdelphij{
61285612Sdelphij	static	struct	in_addr	last_gw;
6254359Sroberto	static	char	last_arp[6] = { 0, 0, 0, 0, 0, 0};
6354359Sroberto	ether_header_t	*eh;
6454359Sroberto	char	*s;
6554359Sroberto	int	err;
66285612Sdelphij
67285612Sdelphij	if (!ethbuf)
68285612Sdelphij		ethbuf = (char *)calloc(1, 65536+1024);
6954359Sroberto	s = ethbuf;
7054359Sroberto	eh = (ether_header_t *)s;
7154359Sroberto
7254359Sroberto	bcopy((char *)buf, s + sizeof(*eh), len);
7354359Sroberto	if (gwip.s_addr == last_gw.s_addr)
74285612Sdelphij		bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
75285612Sdelphij	else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
7654359Sroberto	    {
77285612Sdelphij		perror("arp");
78285612Sdelphij		return -2;
79285612Sdelphij	    }
8054359Sroberto	eh->ether_type = htons(ETHERTYPE_IP);
8154359Sroberto	last_gw.s_addr = gwip.s_addr;
82285612Sdelphij	err = sendip(nfd, s, sizeof(*eh) + len);
83285612Sdelphij	return err;
8454359Sroberto}
85285612Sdelphij
86132451Sroberto
8754359Sroberto/*
88285612Sdelphij */
89330567Sgordonint	send_ip(nfd, mtu, ip, gwip, frag)
90330567Sgordonint	nfd, mtu;
9154359Srobertoip_t	*ip;
92285612Sdelphijstruct	in_addr	gwip;
93285612Sdelphijint	frag;
9454359Sroberto{
9554359Sroberto	static	struct	in_addr	last_gw;
96285612Sdelphij	static	char	last_arp[6] = { 0, 0, 0, 0, 0, 0};
9754359Sroberto	static	u_short	id = 0;
98285612Sdelphij	ether_header_t	*eh;
99330567Sgordon	ip_t	ipsv;
100285612Sdelphij	int	err, iplen;
101330567Sgordon
10254359Sroberto	if (!ipbuf)
10354359Sroberto	  {
104285612Sdelphij		ipbuf = (char *)malloc(65536);
105285612Sdelphij		if(!ipbuf)
106285612Sdelphij		  {
107285612Sdelphij			perror("malloc failed");
108285612Sdelphij			return -2;
109285612Sdelphij		  }
110285612Sdelphij	  }
111285612Sdelphij
112285612Sdelphij	eh = (ether_header_t *)ipbuf;
113285612Sdelphij
114285612Sdelphij	bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost));
115285612Sdelphij	if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr))
116285612Sdelphij		bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
117330567Sgordon	else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
118285612Sdelphij	    {
119285612Sdelphij		perror("arp");
120330567Sgordon		return -2;
121330567Sgordon	    }
122285612Sdelphij	bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp));
123330567Sgordon	eh->ether_type = htons(ETHERTYPE_IP);
124330567Sgordon
125330567Sgordon	bcopy((char *)ip, (char *)&ipsv, sizeof(*ip));
126330567Sgordon	last_gw.s_addr = gwip.s_addr;
127330567Sgordon	iplen = ip->ip_len;
128330567Sgordon	ip->ip_len = htons(iplen);
129330567Sgordon	if (!(frag & 2)) {
130330567Sgordon		if (!ip->ip_v)
131330567Sgordon			ip->ip_v   = IPVERSION;
132330567Sgordon		if (!ip->ip_id)
133330567Sgordon			ip->ip_id  = htons(id++);
134330567Sgordon		if (!ip->ip_ttl)
135330567Sgordon			ip->ip_ttl = 60;
136330567Sgordon	}
137330567Sgordon
138330567Sgordon	if (!frag || (sizeof(*eh) + iplen < mtu))
139330567Sgordon	    {
140330567Sgordon		ip->ip_sum = 0;
141330567Sgordon		ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2);
142330567Sgordon
143330567Sgordon		bcopy((char *)ip, ipbuf + sizeof(*eh), iplen);
144330567Sgordon		err =  sendip(nfd, ipbuf, sizeof(*eh) + iplen);
145330567Sgordon	    }
146330567Sgordon	else
147330567Sgordon	    {
148330567Sgordon		/*
149330567Sgordon		 * Actually, this is bogus because we're putting all IP
150330567Sgordon		 * options in every packet, which isn't always what should be
151330567Sgordon		 * done.  Will do for now.
152330567Sgordon		 */
153330567Sgordon		ether_header_t	eth;
154330567Sgordon		char	optcpy[48], ol;
155330567Sgordon		char	*s;
156330567Sgordon		int	i, sent = 0, ts, hlen, olen;
157330567Sgordon
158330567Sgordon		hlen = ip->ip_hl << 2;
159330567Sgordon		if (mtu < (hlen + 8)) {
160330567Sgordon			fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n",
161330567Sgordon				mtu, hlen);
162330567Sgordon			fprintf(stderr, "can't fragment data\n");
163330567Sgordon			return -2;
164330567Sgordon		}
165330567Sgordon		ol = (ip->ip_hl << 2) - sizeof(*ip);
166330567Sgordon		for (i = 0, s = (char*)(ip + 1); ol > 0; )
167330567Sgordon			if (*s == IPOPT_EOL) {
168330567Sgordon				optcpy[i++] = *s;
169330567Sgordon				break;
170330567Sgordon			} else if (*s == IPOPT_NOP) {
171330567Sgordon				s++;
172330567Sgordon				ol--;
173330567Sgordon			} else
174330567Sgordon			    {
175330567Sgordon				olen = (int)(*(u_char *)(s + 1));
176330567Sgordon				ol -= olen;
177330567Sgordon				if (IPOPT_COPIED(*s))
178330567Sgordon				    {
179330567Sgordon					bcopy(s, optcpy + i, olen);
180330567Sgordon					i += olen;
181330567Sgordon					s += olen;
182330567Sgordon				    }
183330567Sgordon			    }
184330567Sgordon		if (i)
185330567Sgordon		    {
186330567Sgordon			/*
187330567Sgordon			 * pad out
188330567Sgordon			 */
189330567Sgordon			while ((i & 3) && (i & 3) != 3)
190330567Sgordon				optcpy[i++] = IPOPT_NOP;
191330567Sgordon			if ((i & 3) == 3)
192330567Sgordon				optcpy[i++] = IPOPT_EOL;
19354359Sroberto		    }
19454359Sroberto
19554359Sroberto		bcopy((char *)eh, (char *)&eth, sizeof(eth));
19654359Sroberto		s = (char *)ip + hlen;
19754359Sroberto		iplen = ntohs(ip->ip_len) - hlen;
19854359Sroberto		ip->ip_off |= htons(IP_MF);
199285612Sdelphij
200285612Sdelphij		while (1)
201285612Sdelphij		    {
202285612Sdelphij			if ((sent + (mtu - hlen)) >= iplen)
203285612Sdelphij			    {
204285612Sdelphij				ip->ip_off ^= htons(IP_MF);
205285612Sdelphij				ts = iplen - sent;
206285612Sdelphij			    }
207285612Sdelphij			else
208285612Sdelphij				ts = (mtu - hlen);
209285612Sdelphij			ip->ip_off &= htons(0xe000);
210285612Sdelphij			ip->ip_off |= htons(sent >> 3);
211285612Sdelphij			ts += hlen;
212285612Sdelphij			ip->ip_len = htons(ts);
213285612Sdelphij			ip->ip_sum = 0;
214285612Sdelphij			ip->ip_sum = chksum((u_short *)ip, hlen);
215285612Sdelphij			bcopy((char *)ip, ipbuf + sizeof(*eh), hlen);
216285612Sdelphij			bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen);
217285612Sdelphij			err =  sendip(nfd, ipbuf, sizeof(*eh) + ts);
218285612Sdelphij
219285612Sdelphij			bcopy((char *)&eth, ipbuf, sizeof(eth));
220285612Sdelphij			sent += (ts - hlen);
221285612Sdelphij			if (!(ntohs(ip->ip_off) & IP_MF))
222285612Sdelphij				break;
223285612Sdelphij			else if (!(ip->ip_off & htons(0x1fff)))
224285612Sdelphij			    {
22554359Sroberto				hlen = i + sizeof(*ip);
226330567Sgordon				ip->ip_hl = (sizeof(*ip) + i) >> 2;
227330567Sgordon				bcopy(optcpy, (char *)(ip + 1), i);
228330567Sgordon			    }
229330567Sgordon		    }
230285612Sdelphij	    }
231285612Sdelphij
232285612Sdelphij	bcopy((char *)&ipsv, (char *)ip, sizeof(*ip));
233285612Sdelphij	return err;
234285612Sdelphij}
235285612Sdelphij
236285612Sdelphij
237285612Sdelphij/*
238285612Sdelphij * send a tcp packet.
239285612Sdelphij */
240285612Sdelphijint	send_tcp(nfd, mtu, ip, gwip)
241285612Sdelphijint	nfd, mtu;
242285612Sdelphijip_t	*ip;
243293650Sglebiusstruct	in_addr	gwip;
244285612Sdelphij{
245285612Sdelphij	static	tcp_seq	iss = 2;
246285612Sdelphij	struct	tcpiphdr *ti;
247285612Sdelphij	tcphdr_t *t;
248285612Sdelphij	int	thlen, i, iplen, hlen;
249316722Sdelphij	u_32_t	lbuf[20];
250285612Sdelphij
251285612Sdelphij	iplen = ip->ip_len;
252285612Sdelphij	hlen = ip->ip_hl << 2;
253285612Sdelphij	t = (tcphdr_t *)((char *)ip + hlen);
254285612Sdelphij	ti = (struct tcpiphdr *)lbuf;
25554359Sroberto	thlen = t->th_off << 2;
256289997Sglebius	if (!thlen)
257285612Sdelphij		thlen = sizeof(tcphdr_t);
258285612Sdelphij	bzero((char *)ti, sizeof(*ti));
259285612Sdelphij	ip->ip_p = IPPROTO_TCP;
26054359Sroberto	ti->ti_pr = ip->ip_p;
26154359Sroberto	ti->ti_src = ip->ip_src;
262285612Sdelphij	ti->ti_dst = ip->ip_dst;
263285612Sdelphij	bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen);
264285612Sdelphij
265285612Sdelphij	if (!ti->ti_win)
266285612Sdelphij		ti->ti_win = htons(4096);
267285612Sdelphij	iss += 63;
268285612Sdelphij
269293650Sglebius	i = sizeof(struct tcpiphdr) / sizeof(long);
27054359Sroberto
271285612Sdelphij	if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) &&
272285612Sdelphij	    (lbuf[i] != htonl(0x020405b4))) {
273285612Sdelphij		lbuf[i] = htonl(0x020405b4);
274285612Sdelphij		bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4,
275316722Sdelphij		      iplen - thlen - hlen);
276285612Sdelphij		thlen += 4;
277285612Sdelphij	    }
278285612Sdelphij	ti->ti_off = thlen >> 2;
279285612Sdelphij	ti->ti_len = htons(thlen);
280285612Sdelphij	ip->ip_len = hlen + thlen;
281285612Sdelphij	ti->ti_sum = 0;
282289997Sglebius	ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
283285612Sdelphij
284285612Sdelphij	bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen);
28554359Sroberto	return send_ip(nfd, mtu, ip, gwip, 1);
28654359Sroberto}
28754359Sroberto
288285612Sdelphij
289285612Sdelphij/*
290285612Sdelphij * send a udp packet.
291285612Sdelphij */
292285612Sdelphijint	send_udp(nfd, mtu, ip, gwip)
293285612Sdelphijint	nfd, mtu;
294285612Sdelphijip_t	*ip;
295285612Sdelphijstruct	in_addr	gwip;
296285612Sdelphij{
297285612Sdelphij	struct	tcpiphdr *ti;
298330567Sgordon	int	thlen;
299285612Sdelphij	u_long	lbuf[20];
300285612Sdelphij
301285612Sdelphij	ti = (struct tcpiphdr *)lbuf;
302285612Sdelphij	bzero((char *)ti, sizeof(*ti));
303285612Sdelphij	thlen = sizeof(udphdr_t);
304285612Sdelphij	ti->ti_pr = ip->ip_p;
305285612Sdelphij	ti->ti_src = ip->ip_src;
306289997Sglebius	ti->ti_dst = ip->ip_dst;
307285612Sdelphij	bcopy((char *)ip + (ip->ip_hl << 2),
308285612Sdelphij	      (char *)&ti->ti_sport, sizeof(udphdr_t));
309285612Sdelphij
310285612Sdelphij	ti->ti_len = htons(thlen);
311285612Sdelphij	ip->ip_len = (ip->ip_hl << 2) + thlen;
312285612Sdelphij	ti->ti_sum = 0;
313285612Sdelphij	ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
314285612Sdelphij
315285612Sdelphij	bcopy((char *)&ti->ti_sport,
316285612Sdelphij	      (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t));
317285612Sdelphij	return send_ip(nfd, mtu, ip, gwip, 1);
318285612Sdelphij}
319285612Sdelphij
320285612Sdelphij
321285612Sdelphij/*
322285612Sdelphij * send an icmp packet.
323285612Sdelphij */
324285612Sdelphijint	send_icmp(nfd, mtu, ip, gwip)
325285612Sdelphijint	nfd, mtu;
326285612Sdelphijip_t	*ip;
327285612Sdelphijstruct	in_addr	gwip;
328285612Sdelphij{
329285612Sdelphij	struct	icmp	*ic;
330285612Sdelphij
331285612Sdelphij	ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
332285612Sdelphij
333285612Sdelphij	ic->icmp_cksum = 0;
334285612Sdelphij	ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp));
335285612Sdelphij
336285612Sdelphij	return send_ip(nfd, mtu, ip, gwip, 1);
337285612Sdelphij}
338285612Sdelphij
339285612Sdelphij
340285612Sdelphijint	send_packet(nfd, mtu, ip, gwip)
341285612Sdelphijint	nfd, mtu;
342285612Sdelphijip_t	*ip;
343285612Sdelphijstruct	in_addr	gwip;
344285612Sdelphij{
345285612Sdelphij        switch (ip->ip_p)
346285612Sdelphij        {
347285612Sdelphij        case IPPROTO_TCP :
348330567Sgordon                return send_tcp(nfd, mtu, ip, gwip);
349330567Sgordon        case IPPROTO_UDP :
350285612Sdelphij                return send_udp(nfd, mtu, ip, gwip);
351330567Sgordon        case IPPROTO_ICMP :
352330567Sgordon                return send_icmp(nfd, mtu, ip, gwip);
353330567Sgordon        default :
354330567Sgordon                return send_ip(nfd, mtu, ip, gwip, 1);
355330567Sgordon        }
356330567Sgordon}
357330567Sgordon