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