- Test m_pkthdr.fw_flags against DUMMYNET_MBUF_TAGGED before trying to locate
[dragonfly/netmp.git] / contrib / ipfilter / ipsend / ip.c
blob8d30bf5031ac0e662908145a85a85b250e8c040c
1 /*
2 * ip.c (C) 1995-1998 Darren Reed
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
8 #endif
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <netinet/in_systm.h>
16 #include <sys/socket.h>
17 #include <net/if.h>
18 #include <netinet/in.h>
19 #include <netinet/ip.h>
20 #include <netinet/tcp.h>
21 #include <netinet/udp.h>
22 #include <netinet/ip_icmp.h>
23 #include <sys/param.h>
24 #ifndef linux
25 # include <netinet/if_ether.h>
26 # include <netinet/ip_var.h>
27 # if __FreeBSD_version >= 300000
28 # include <net/if_var.h>
29 # endif
30 #endif
31 #include "ipsend.h"
33 #if !defined(lint)
34 static const char sccsid[] = "%W% %G% (C)1995";
35 static const char rcsid[] = "@(#)$Id: ip.c,v 2.1.4.5 2002/12/06 11:40:35 darrenr Exp $";
36 #endif
38 static char *ipbuf = NULL, *ethbuf = NULL;
41 u_short chksum(buf,len)
42 u_short *buf;
43 int len;
45 u_long sum = 0;
46 int nwords = len >> 1;
48 for(; nwords > 0; nwords--)
49 sum += *buf++;
50 sum = (sum>>16) + (sum & 0xffff);
51 sum += (sum >>16);
52 return (~sum);
56 int send_ether(nfd, buf, len, gwip)
57 int nfd, len;
58 char *buf;
59 struct in_addr gwip;
61 static struct in_addr last_gw;
62 static char last_arp[6] = { 0, 0, 0, 0, 0, 0};
63 ether_header_t *eh;
64 char *s;
65 int err;
67 if (!ethbuf)
68 ethbuf = (char *)calloc(1, 65536+1024);
69 s = ethbuf;
70 eh = (ether_header_t *)s;
72 bcopy((char *)buf, s + sizeof(*eh), len);
73 if (gwip.s_addr == last_gw.s_addr)
74 bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
75 else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
77 perror("arp");
78 return -2;
80 eh->ether_type = htons(ETHERTYPE_IP);
81 last_gw.s_addr = gwip.s_addr;
82 err = sendip(nfd, s, sizeof(*eh) + len);
83 return err;
89 int send_ip(nfd, mtu, ip, gwip, frag)
90 int nfd, mtu;
91 ip_t *ip;
92 struct in_addr gwip;
93 int frag;
95 static struct in_addr last_gw;
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;
102 if (!ipbuf)
104 ipbuf = (char *)malloc(65536);
105 if(!ipbuf)
107 perror("malloc failed");
108 return -2;
112 eh = (ether_header_t *)ipbuf;
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 bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
117 else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
119 perror("arp");
120 return -2;
122 bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp));
123 eh->ether_type = htons(ETHERTYPE_IP);
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->ip_v)
131 ip->ip_v = IPVERSION;
132 if (!ip->ip_id)
133 ip->ip_id = htons(id++);
134 if (!ip->ip_ttl)
135 ip->ip_ttl = 60;
138 if (!frag || (sizeof(*eh) + iplen < mtu))
140 ip->ip_sum = 0;
141 ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2);
143 bcopy((char *)ip, ipbuf + sizeof(*eh), iplen);
144 err = sendip(nfd, ipbuf, sizeof(*eh) + iplen);
146 else
149 * Actually, this is bogus because we're putting all IP
150 * options in every packet, which isn't always what should be
151 * done. Will do for now.
153 ether_header_t eth;
154 char optcpy[48], ol;
155 char *s;
156 int i, sent = 0, ts, hlen, olen;
158 hlen = ip->ip_hl << 2;
159 if (mtu < (hlen + 8)) {
160 fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n",
161 mtu, hlen);
162 fprintf(stderr, "can't fragment data\n");
163 return -2;
165 ol = (ip->ip_hl << 2) - sizeof(*ip);
166 for (i = 0, s = (char*)(ip + 1); ol > 0; )
167 if (*s == IPOPT_EOL) {
168 optcpy[i++] = *s;
169 break;
170 } else if (*s == IPOPT_NOP) {
171 s++;
172 ol--;
173 } else
175 olen = (int)(*(u_char *)(s + 1));
176 ol -= olen;
177 if (IPOPT_COPIED(*s))
179 bcopy(s, optcpy + i, olen);
180 i += olen;
181 s += olen;
184 if (i)
187 * pad out
189 while ((i & 3) && (i & 3) != 3)
190 optcpy[i++] = IPOPT_NOP;
191 if ((i & 3) == 3)
192 optcpy[i++] = IPOPT_EOL;
195 bcopy((char *)eh, (char *)&eth, sizeof(eth));
196 s = (char *)ip + hlen;
197 iplen = ntohs(ip->ip_len) - hlen;
198 ip->ip_off |= htons(IP_MF);
200 while (1)
202 if ((sent + (mtu - hlen)) >= iplen)
204 ip->ip_off ^= htons(IP_MF);
205 ts = iplen - sent;
207 else
208 ts = (mtu - hlen);
209 ip->ip_off &= htons(0xe000);
210 ip->ip_off |= htons(sent >> 3);
211 ts += hlen;
212 ip->ip_len = htons(ts);
213 ip->ip_sum = 0;
214 ip->ip_sum = chksum((u_short *)ip, hlen);
215 bcopy((char *)ip, ipbuf + sizeof(*eh), hlen);
216 bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen);
217 err = sendip(nfd, ipbuf, sizeof(*eh) + ts);
219 bcopy((char *)&eth, ipbuf, sizeof(eth));
220 sent += (ts - hlen);
221 if (!(ntohs(ip->ip_off) & IP_MF))
222 break;
223 else if (!(ip->ip_off & htons(0x1fff)))
225 hlen = i + sizeof(*ip);
226 ip->ip_hl = (sizeof(*ip) + i) >> 2;
227 bcopy(optcpy, (char *)(ip + 1), i);
232 bcopy((char *)&ipsv, (char *)ip, sizeof(*ip));
233 return err;
238 * send a tcp packet.
240 int send_tcp(nfd, mtu, ip, gwip)
241 int nfd, mtu;
242 ip_t *ip;
243 struct in_addr gwip;
245 static tcp_seq iss = 2;
246 struct tcpiphdr *ti;
247 tcphdr_t *t;
248 int thlen, i, iplen, hlen;
249 u_32_t lbuf[20];
251 iplen = ip->ip_len;
252 hlen = ip->ip_hl << 2;
253 t = (tcphdr_t *)((char *)ip + hlen);
254 ti = (struct tcpiphdr *)lbuf;
255 thlen = t->th_off << 2;
256 if (!thlen)
257 thlen = sizeof(tcphdr_t);
258 bzero((char *)ti, sizeof(*ti));
259 ip->ip_p = IPPROTO_TCP;
260 ti->ti_pr = ip->ip_p;
261 ti->ti_src = ip->ip_src;
262 ti->ti_dst = ip->ip_dst;
263 bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen);
265 if (!ti->ti_win)
266 ti->ti_win = htons(4096);
267 iss += 63;
269 i = sizeof(struct tcpiphdr) / sizeof(long);
271 if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) &&
272 (lbuf[i] != htonl(0x020405b4))) {
273 lbuf[i] = htonl(0x020405b4);
274 bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4,
275 iplen - thlen - hlen);
276 thlen += 4;
278 ti->ti_off = thlen >> 2;
279 ti->ti_len = htons(thlen);
280 ip->ip_len = hlen + thlen;
281 ti->ti_sum = 0;
282 ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
284 bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen);
285 return send_ip(nfd, mtu, ip, gwip, 1);
290 * send a udp packet.
292 int send_udp(nfd, mtu, ip, gwip)
293 int nfd, mtu;
294 ip_t *ip;
295 struct in_addr gwip;
297 struct tcpiphdr *ti;
298 int thlen;
299 u_long lbuf[20];
301 ti = (struct tcpiphdr *)lbuf;
302 bzero((char *)ti, sizeof(*ti));
303 thlen = sizeof(udphdr_t);
304 ti->ti_pr = ip->ip_p;
305 ti->ti_src = ip->ip_src;
306 ti->ti_dst = ip->ip_dst;
307 bcopy((char *)ip + (ip->ip_hl << 2),
308 (char *)&ti->ti_sport, sizeof(udphdr_t));
310 ti->ti_len = htons(thlen);
311 ip->ip_len = (ip->ip_hl << 2) + thlen;
312 ti->ti_sum = 0;
313 ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
315 bcopy((char *)&ti->ti_sport,
316 (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t));
317 return send_ip(nfd, mtu, ip, gwip, 1);
322 * send an icmp packet.
324 int send_icmp(nfd, mtu, ip, gwip)
325 int nfd, mtu;
326 ip_t *ip;
327 struct in_addr gwip;
329 struct icmp *ic;
331 ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
333 ic->icmp_cksum = 0;
334 ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp));
336 return send_ip(nfd, mtu, ip, gwip, 1);
340 int send_packet(nfd, mtu, ip, gwip)
341 int nfd, mtu;
342 ip_t *ip;
343 struct in_addr gwip;
345 switch (ip->ip_p)
347 case IPPROTO_TCP :
348 return send_tcp(nfd, mtu, ip, gwip);
349 case IPPROTO_UDP :
350 return send_udp(nfd, mtu, ip, gwip);
351 case IPPROTO_ICMP :
352 return send_icmp(nfd, mtu, ip, gwip);
353 default :
354 return send_ip(nfd, mtu, ip, gwip, 1);