1
2/*
3 * ip.c (C) 1995-1998 Darren Reed
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7#include <sys/param.h>
8#include <sys/types.h>
9#include <netinet/in_systm.h>
10#include <sys/socket.h>
11#include <net/if.h>
12#include <netinet/in.h>
13#include <netinet/ip.h>
14#include <sys/param.h>
15# include <net/route.h>
16# include <netinet/if_ether.h>
17# include <netinet/ip_var.h>
18#include <errno.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23#include "ipsend.h"
24
25
26static	char	*ipbuf = NULL, *ethbuf = NULL;
27
28
29u_short
30chksum(u_short *buf, int len)
31{
32	u_long	sum = 0;
33	int	nwords = len >> 1;
34
35	for(; nwords > 0; nwords--)
36		sum += *buf++;
37	sum = (sum>>16) + (sum & 0xffff);
38	sum += (sum >>16);
39	return (~sum);
40}
41
42
43int
44send_ether(int nfd, char *buf, int len, struct in_addr gwip)
45{
46	static	struct	in_addr	last_gw;
47	static	char	last_arp[6] = { 0, 0, 0, 0, 0, 0};
48	ether_header_t	*eh;
49	char	*s;
50	int	err;
51
52	if (!ethbuf)
53		ethbuf = (char *)calloc(1, 65536+1024);
54	s = ethbuf;
55	eh = (ether_header_t *)s;
56
57	bcopy((char *)buf, s + sizeof(*eh), len);
58	if (gwip.s_addr == last_gw.s_addr)
59	    {
60		bcopy(last_arp, (char *) &eh->ether_dhost, 6);
61	    }
62	else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1)
63	    {
64		perror("arp");
65		return (-2);
66	    }
67	eh->ether_type = htons(ETHERTYPE_IP);
68	last_gw.s_addr = gwip.s_addr;
69	err = sendip(nfd, s, sizeof(*eh) + len);
70	return (err);
71}
72
73
74/*
75 */
76int
77send_ip(int nfd, int mtu, ip_t *ip, struct in_addr gwip, int frag)
78{
79	static	struct	in_addr	last_gw, local_ip;
80	static	char	local_arp[6] = { 0, 0, 0, 0, 0, 0};
81	static	char	last_arp[6] = { 0, 0, 0, 0, 0, 0};
82	static	u_short	id = 0;
83	ether_header_t	*eh;
84	ip_t	ipsv;
85	int	err, iplen;
86
87	if (!ipbuf)
88	  {
89		ipbuf = (char *)malloc(65536);
90		if (!ipbuf)
91		  {
92			perror("malloc failed");
93			return (-2);
94		  }
95	  }
96
97	eh = (ether_header_t *)ipbuf;
98
99	bzero((char *) &eh->ether_shost, sizeof(eh->ether_shost));
100	if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr))
101	    {
102		bcopy(last_arp, (char *) &eh->ether_dhost, 6);
103	    }
104	else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1)
105	    {
106		perror("arp");
107		return (-2);
108	    }
109	bcopy((char *) &eh->ether_dhost, last_arp, sizeof(last_arp));
110	eh->ether_type = htons(ETHERTYPE_IP);
111
112	bcopy((char *)ip, (char *)&ipsv, sizeof(*ip));
113	last_gw.s_addr = gwip.s_addr;
114	iplen = ip->ip_len;
115	ip->ip_len = htons(iplen);
116	if (!(frag & 2)) {
117		if (!IP_V(ip))
118			IP_V_A(ip, IPVERSION);
119		if (!ip->ip_id)
120			ip->ip_id  = htons(id++);
121		if (!ip->ip_ttl)
122			ip->ip_ttl = 60;
123	}
124
125	if (ip->ip_src.s_addr != local_ip.s_addr) {
126		(void) arp((char *)&ip->ip_src, (char *) &local_arp);
127		bcopy(local_arp, (char *) &eh->ether_shost,sizeof(last_arp));
128		local_ip = ip->ip_src;
129	} else
130		bcopy(local_arp, (char *) &eh->ether_shost, 6);
131
132	if (!frag || (sizeof(*eh) + iplen < mtu))
133	    {
134		ip->ip_sum = 0;
135		ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2);
136
137		bcopy((char *)ip, ipbuf + sizeof(*eh), iplen);
138		err =  sendip(nfd, ipbuf, sizeof(*eh) + iplen);
139	    }
140	else
141	    {
142		/*
143		 * Actually, this is bogus because we're putting all IP
144		 * options in every packet, which isn't always what should be
145		 * done.  Will do for now.
146		 */
147		ether_header_t	eth;
148		char	optcpy[48], ol;
149		char	*s;
150		int	i, sent = 0, ts, hlen, olen;
151
152		hlen = IP_HL(ip) << 2;
153		if (mtu < (hlen + 8)) {
154			fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n",
155				mtu, hlen);
156			fprintf(stderr, "can't fragment data\n");
157			return (-2);
158		}
159		ol = (IP_HL(ip) << 2) - sizeof(*ip);
160		for (i = 0, s = (char*)(ip + 1); ol > 0; )
161			if (*s == IPOPT_EOL) {
162				optcpy[i++] = *s;
163				break;
164			} else if (*s == IPOPT_NOP) {
165				s++;
166				ol--;
167			} else
168			    {
169				olen = (int)(*(u_char *)(s + 1));
170				ol -= olen;
171				if (IPOPT_COPIED(*s))
172				    {
173					bcopy(s, optcpy + i, olen);
174					i += olen;
175					s += olen;
176				    }
177			    }
178		if (i)
179		    {
180			/*
181			 * pad out
182			 */
183			while ((i & 3) && (i & 3) != 3)
184				optcpy[i++] = IPOPT_NOP;
185			if ((i & 3) == 3)
186				optcpy[i++] = IPOPT_EOL;
187		    }
188
189		bcopy((char *)eh, (char *)&eth, sizeof(eth));
190		s = (char *)ip + hlen;
191		iplen = ntohs(ip->ip_len) - hlen;
192		ip->ip_off |= htons(IP_MF);
193
194		while (1)
195		    {
196			if ((sent + (mtu - hlen)) >= iplen)
197			    {
198				ip->ip_off ^= htons(IP_MF);
199				ts = iplen - sent;
200			    }
201			else
202				ts = (mtu - hlen);
203			ip->ip_off &= htons(0xe000);
204			ip->ip_off |= htons(sent >> 3);
205			ts += hlen;
206			ip->ip_len = htons(ts);
207			ip->ip_sum = 0;
208			ip->ip_sum = chksum((u_short *)ip, hlen);
209			bcopy((char *)ip, ipbuf + sizeof(*eh), hlen);
210			bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen);
211			err =  sendip(nfd, ipbuf, sizeof(*eh) + ts);
212
213			bcopy((char *)&eth, ipbuf, sizeof(eth));
214			sent += (ts - hlen);
215			if (!(ntohs(ip->ip_off) & IP_MF))
216				break;
217			else if (!(ip->ip_off & htons(0x1fff)))
218			    {
219				hlen = i + sizeof(*ip);
220				IP_HL_A(ip, (sizeof(*ip) + i) >> 2);
221				bcopy(optcpy, (char *)(ip + 1), i);
222			    }
223		    }
224	    }
225
226	bcopy((char *)&ipsv, (char *)ip, sizeof(*ip));
227	return (err);
228}
229
230
231/*
232 * send a tcp packet.
233 */
234int
235send_tcp(int nfd, int mtu, ip_t *ip, struct in_addr gwip)
236{
237	static	tcp_seq	iss = 2;
238	tcphdr_t *t, *t2;
239	int	thlen, i, iplen, hlen;
240	u_32_t	lbuf[20];
241	ip_t	*ip2;
242
243	iplen = ip->ip_len;
244	hlen = IP_HL(ip) << 2;
245	t = (tcphdr_t *)((char *)ip + hlen);
246	ip2 = (struct ip *)lbuf;
247	t2 = (tcphdr_t *)((char *)ip2 + hlen);
248	thlen = TCP_OFF(t) << 2;
249	if (!thlen)
250		thlen = sizeof(tcphdr_t);
251	bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2));
252	ip->ip_p = IPPROTO_TCP;
253	ip2->ip_p = ip->ip_p;
254	ip2->ip_src = ip->ip_src;
255	ip2->ip_dst = ip->ip_dst;
256	bcopy((char *)ip + hlen, (char *)t2, thlen);
257
258	if (!t2->th_win)
259		t2->th_win = htons(4096);
260	iss += 63;
261
262	i = sizeof(struct tcpiphdr) / sizeof(long);
263
264	if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) &&
265	    (lbuf[i] != htonl(0x020405b4))) {
266		lbuf[i] = htonl(0x020405b4);
267		bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4,
268		      iplen - thlen - hlen);
269		thlen += 4;
270	    }
271	TCP_OFF_A(t2, thlen >> 2);
272	ip2->ip_len = htons(thlen);
273	ip->ip_len = hlen + thlen;
274	t2->th_sum = 0;
275	t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t));
276
277	bcopy((char *)t2, (char *)ip + hlen, thlen);
278	return (send_ip(nfd, mtu, ip, gwip, 1));
279}
280
281
282/*
283 * send a udp packet.
284 */
285int
286send_udp(int nfd, int mtu, ip_t *ip, struct in_addr gwip)
287{
288	struct	tcpiphdr *ti;
289	int	thlen;
290	u_long	lbuf[20];
291
292	ti = (struct tcpiphdr *)lbuf;
293	bzero((char *)ti, sizeof(*ti));
294	thlen = sizeof(udphdr_t);
295	ti->ti_pr = ip->ip_p;
296	ti->ti_src = ip->ip_src;
297	ti->ti_dst = ip->ip_dst;
298	bcopy((char *)ip + (IP_HL(ip) << 2),
299	      (char *)&ti->ti_sport, sizeof(udphdr_t));
300
301	ti->ti_len = htons(thlen);
302	ip->ip_len = (IP_HL(ip) << 2) + thlen;
303	ti->ti_sum = 0;
304	ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
305
306	bcopy((char *)&ti->ti_sport,
307	      (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t));
308	return (send_ip(nfd, mtu, ip, gwip, 1));
309}
310
311
312/*
313 * send an icmp packet.
314 */
315int
316send_icmp(int nfd, int mtu, ip_t *ip, in_addr gwip)
317{
318	struct	icmp	*ic;
319
320	ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2));
321
322	ic->icmp_cksum = 0;
323	ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp));
324
325	return (send_ip(nfd, mtu, ip, gwip, 1));
326}
327
328
329int
330send_packet(int nfd, int mtu, ip_t *ip, struct in_addr gwip)
331	int	nfd, mtu;
332	ip_t	*ip;
333	struct	in_addr	gwip;
334{
335	switch (ip->ip_p)
336	{
337	case IPPROTO_TCP :
338(                return send_tcp(nfd, mtu, ip, gwip));
339	case IPPROTO_UDP :
340(                return send_udp(nfd, mtu, ip, gwip));
341	case IPPROTO_ICMP :
342(                return send_icmp(nfd, mtu, ip, gwip));
343	default :
344(                return send_ip(nfd, mtu, ip, gwip, 1));
345	}
346}
347