2 * ip.c (C) 1995-1998 Darren Reed
4 * See the IPFILTER.LICENCE file for details on licencing.
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
14 #include <sys/types.h>
15 #include <netinet/in_systm.h>
16 #include <sys/socket.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>
25 # include <netinet/if_ether.h>
26 # include <netinet/ip_var.h>
27 # if __FreeBSD_version >= 300000
28 # include <net/if_var.h>
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 $";
38 static char *ipbuf
= NULL
, *ethbuf
= NULL
;
41 u_short
chksum(buf
,len
)
46 int nwords
= len
>> 1;
48 for(; nwords
> 0; nwords
--)
50 sum
= (sum
>>16) + (sum
& 0xffff);
56 int send_ether(nfd
, buf
, len
, gwip
)
61 static struct in_addr last_gw
;
62 static char last_arp
[6] = { 0, 0, 0, 0, 0, 0};
68 ethbuf
= (char *)calloc(1, 65536+1024);
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)
80 eh
->ether_type
= htons(ETHERTYPE_IP
);
81 last_gw
.s_addr
= gwip
.s_addr
;
82 err
= sendip(nfd
, s
, sizeof(*eh
) + len
);
89 int send_ip(nfd
, mtu
, ip
, gwip
, 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;
104 ipbuf
= (char *)malloc(65536);
107 perror("malloc failed");
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)
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
;
128 ip
->ip_len
= htons(iplen
);
131 ip
->ip_v
= IPVERSION
;
133 ip
->ip_id
= htons(id
++);
138 if (!frag
|| (sizeof(*eh
) + iplen
< mtu
))
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
);
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.
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",
162 fprintf(stderr
, "can't fragment data\n");
165 ol
= (ip
->ip_hl
<< 2) - sizeof(*ip
);
166 for (i
= 0, s
= (char*)(ip
+ 1); ol
> 0; )
167 if (*s
== IPOPT_EOL
) {
170 } else if (*s
== IPOPT_NOP
) {
175 olen
= (int)(*(u_char
*)(s
+ 1));
177 if (IPOPT_COPIED(*s
))
179 bcopy(s
, optcpy
+ i
, olen
);
189 while ((i
& 3) && (i
& 3) != 3)
190 optcpy
[i
++] = IPOPT_NOP
;
192 optcpy
[i
++] = IPOPT_EOL
;
195 bcopy((char *)eh
, (char *)ð
, sizeof(eth
));
196 s
= (char *)ip
+ hlen
;
197 iplen
= ntohs(ip
->ip_len
) - hlen
;
198 ip
->ip_off
|= htons(IP_MF
);
202 if ((sent
+ (mtu
- hlen
)) >= iplen
)
204 ip
->ip_off
^= htons(IP_MF
);
209 ip
->ip_off
&= htons(0xe000);
210 ip
->ip_off
|= htons(sent
>> 3);
212 ip
->ip_len
= htons(ts
);
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 *)ð
, ipbuf
, sizeof(eth
));
221 if (!(ntohs(ip
->ip_off
) & IP_MF
))
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
));
240 int send_tcp(nfd
, mtu
, ip
, gwip
)
245 static tcp_seq iss
= 2;
248 int thlen
, i
, iplen
, hlen
;
252 hlen
= ip
->ip_hl
<< 2;
253 t
= (tcphdr_t
*)((char *)ip
+ hlen
);
254 ti
= (struct tcpiphdr
*)lbuf
;
255 thlen
= t
->th_off
<< 2;
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
);
266 ti
->ti_win
= htons(4096);
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
);
278 ti
->ti_off
= thlen
>> 2;
279 ti
->ti_len
= htons(thlen
);
280 ip
->ip_len
= hlen
+ thlen
;
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);
292 int send_udp(nfd
, mtu
, ip
, gwip
)
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
;
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
)
331 ic
= (struct icmp
*)((char *)ip
+ (ip
->ip_hl
<< 2));
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
)
348 return send_tcp(nfd
, mtu
, ip
, gwip
);
350 return send_udp(nfd
, mtu
, ip
, gwip
);
352 return send_icmp(nfd
, mtu
, ip
, gwip
);
354 return send_ip(nfd
, mtu
, ip
, gwip
, 1);