xref: /freebsd/sbin/ipf/ipsend/ip.c (revision 8aac90f18aef7c9eea906c3ff9a001ca7b94f375)
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 
26 static	char	*ipbuf = NULL, *ethbuf = NULL;
27 
28 
29 u_short
30 chksum(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 
43 int
44 send_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  */
76 int
77 send_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  */
234 int
235 send_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  */
285 int
286 send_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  */
315 int
316 send_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 
329 int
330 send_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