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