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