ip.c revision 145510
1/* $NetBSD$ */ 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) 9static const char sccsid[] = "%W% %G% (C)1995"; 10static 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 35static char *ipbuf = NULL, *ethbuf = NULL; 36 37 38u_short chksum(buf,len) 39u_short *buf; 40int 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 53int send_ether(nfd, buf, len, gwip) 54int nfd, len; 55char *buf; 56struct 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 */ 88int send_ip(nfd, mtu, ip, gwip, frag) 89int nfd, mtu; 90ip_t *ip; 91struct in_addr gwip; 92int 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 *)ð, 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 *)ð, 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 */ 249int send_tcp(nfd, mtu, ip, gwip) 250int nfd, mtu; 251ip_t *ip; 252struct 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 */ 302int send_udp(nfd, mtu, ip, gwip) 303int nfd, mtu; 304ip_t *ip; 305struct 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 */ 334int send_icmp(nfd, mtu, ip, gwip) 335int nfd, mtu; 336ip_t *ip; 337struct 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 350int send_packet(nfd, mtu, ip, gwip) 351int nfd, mtu; 352ip_t *ip; 353struct 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} 367