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
chksum(u_short * buf,int len)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
send_ether(int nfd,char * buf,int len,struct in_addr gwip)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
send_ip(int nfd,int mtu,ip_t * ip,struct in_addr gwip,int frag)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 *)ð, 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 *)ð, 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
send_tcp(int nfd,int mtu,ip_t * ip,struct in_addr gwip)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 ((__tcp_get_flags(t2) == 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
send_udp(int nfd,int mtu,ip_t * ip,struct in_addr gwip)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
send_icmp(int nfd,int mtu,ip_t * ip,in_addr gwip)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