ip.c revision 80486
1203181Smarcel/* 2203181Smarcel * ip.c (C) 1995-1998 Darren Reed 3203181Smarcel * 4203181Smarcel * See the IPFILTER.LICENCE file for details on licencing. 5203181Smarcel */ 6203181Smarcel#include <errno.h> 7203181Smarcel#include <stdio.h> 8203181Smarcel#include <stdlib.h> 9203181Smarcel#include <unistd.h> 10203181Smarcel#include <string.h> 11203181Smarcel#include <sys/types.h> 12203181Smarcel#include <netinet/in_systm.h> 13203181Smarcel#include <sys/socket.h> 14203181Smarcel#include <net/if.h> 15203181Smarcel#include <netinet/in.h> 16203181Smarcel#include <netinet/ip.h> 17203181Smarcel#include <netinet/tcp.h> 18203181Smarcel#include <netinet/udp.h> 19203181Smarcel#include <netinet/ip_icmp.h> 20203181Smarcel#include <sys/param.h> 21203181Smarcel#ifndef linux 22203181Smarcel# include <netinet/if_ether.h> 23203181Smarcel# include <netinet/ip_var.h> 24203181Smarcel# if __FreeBSD_version >= 300000 25203181Smarcel# include <net/if_var.h> 26203181Smarcel# endif 27203181Smarcel#endif 28203181Smarcel#include "ipsend.h" 29203181Smarcel 30203181Smarcel#if !defined(lint) 31203181Smarcelstatic const char sccsid[] = "%W% %G% (C)1995"; 32203181Smarcelstatic const char rcsid[] = "@(#)$Id: ip.c,v 2.1.4.3 2001/07/15 22:00:13 darrenr Exp $"; 33203181Smarcel#endif 34203181Smarcel 35203181Smarcelstatic char *ipbuf = NULL, *ethbuf = NULL; 36203181Smarcel 37203181Smarcel 38203181Smarcelu_short chksum(buf,len) 39203181Smarcelu_short *buf; 40203181Smarcelint len; 41203181Smarcel{ 42203181Smarcel u_long sum = 0; 43203181Smarcel int nwords = len >> 1; 44203181Smarcel 45203181Smarcel for(; nwords > 0; nwords--) 46203181Smarcel sum += *buf++; 47203181Smarcel sum = (sum>>16) + (sum & 0xffff); 48203181Smarcel sum += (sum >>16); 49203181Smarcel return (~sum); 50203181Smarcel} 51203181Smarcel 52203181Smarcel 53203181Smarcelint send_ether(nfd, buf, len, gwip) 54203181Smarcelint nfd, len; 55203181Smarcelchar *buf; 56203181Smarcelstruct in_addr gwip; 57203181Smarcel{ 58203181Smarcel static struct in_addr last_gw; 59203181Smarcel static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 60203181Smarcel ether_header_t *eh; 61203181Smarcel char *s; 62203181Smarcel int err; 63203181Smarcel 64203181Smarcel if (!ethbuf) 65203181Smarcel ethbuf = (char *)calloc(1, 65536+1024); 66203181Smarcel s = ethbuf; 67203181Smarcel eh = (ether_header_t *)s; 68203181Smarcel 69 bcopy((char *)buf, s + sizeof(*eh), len); 70 if (gwip.s_addr == last_gw.s_addr) 71 bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 72 else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 73 { 74 perror("arp"); 75 return -2; 76 } 77 eh->ether_type = htons(ETHERTYPE_IP); 78 last_gw.s_addr = gwip.s_addr; 79 err = sendip(nfd, s, sizeof(*eh) + len); 80 return err; 81} 82 83 84/* 85 */ 86int send_ip(nfd, mtu, ip, gwip, frag) 87int nfd, mtu; 88ip_t *ip; 89struct in_addr gwip; 90int frag; 91{ 92 static struct in_addr last_gw; 93 static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 94 static u_short id = 0; 95 ether_header_t *eh; 96 ip_t ipsv; 97 int err, iplen; 98 99 if (!ipbuf) 100 { 101 ipbuf = (char *)malloc(65536); 102 if(!ipbuf) 103 { 104 perror("malloc failed"); 105 return -2; 106 } 107 } 108 109 eh = (ether_header_t *)ipbuf; 110 111 bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); 112 if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 113 bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 114 else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 115 { 116 perror("arp"); 117 return -2; 118 } 119 bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); 120 eh->ether_type = htons(ETHERTYPE_IP); 121 122 bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 123 last_gw.s_addr = gwip.s_addr; 124 iplen = ip->ip_len; 125 ip->ip_len = htons(iplen); 126 if (!(frag & 2)) { 127 if (!ip->ip_v) 128 ip->ip_v = IPVERSION; 129 if (!ip->ip_id) 130 ip->ip_id = htons(id++); 131 if (!ip->ip_ttl) 132 ip->ip_ttl = 60; 133 } 134 135 if (!frag || (sizeof(*eh) + iplen < mtu)) 136 { 137 ip->ip_sum = 0; 138 ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); 139 140 bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); 141 err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); 142 } 143 else 144 { 145 /* 146 * Actually, this is bogus because we're putting all IP 147 * options in every packet, which isn't always what should be 148 * done. Will do for now. 149 */ 150 ether_header_t eth; 151 char optcpy[48], ol; 152 char *s; 153 int i, sent = 0, ts, hlen, olen; 154 155 hlen = ip->ip_hl << 2; 156 if (mtu < (hlen + 8)) { 157 fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 158 mtu, hlen); 159 fprintf(stderr, "can't fragment data\n"); 160 return -2; 161 } 162 ol = (ip->ip_hl << 2) - sizeof(*ip); 163 for (i = 0, s = (char*)(ip + 1); ol > 0; ) 164 if (*s == IPOPT_EOL) { 165 optcpy[i++] = *s; 166 break; 167 } else if (*s == IPOPT_NOP) { 168 s++; 169 ol--; 170 } else 171 { 172 olen = (int)(*(u_char *)(s + 1)); 173 ol -= olen; 174 if (IPOPT_COPIED(*s)) 175 { 176 bcopy(s, optcpy + i, olen); 177 i += olen; 178 s += olen; 179 } 180 } 181 if (i) 182 { 183 /* 184 * pad out 185 */ 186 while ((i & 3) && (i & 3) != 3) 187 optcpy[i++] = IPOPT_NOP; 188 if ((i & 3) == 3) 189 optcpy[i++] = IPOPT_EOL; 190 } 191 192 bcopy((char *)eh, (char *)ð, sizeof(eth)); 193 s = (char *)ip + hlen; 194 iplen = ntohs(ip->ip_len) - hlen; 195 ip->ip_off |= htons(IP_MF); 196 197 while (1) 198 { 199 if ((sent + (mtu - hlen)) >= iplen) 200 { 201 ip->ip_off ^= htons(IP_MF); 202 ts = iplen - sent; 203 } 204 else 205 ts = (mtu - hlen); 206 ip->ip_off &= htons(0xe000); 207 ip->ip_off |= htons(sent >> 3); 208 ts += hlen; 209 ip->ip_len = htons(ts); 210 ip->ip_sum = 0; 211 ip->ip_sum = chksum((u_short *)ip, hlen); 212 bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 213 bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 214 err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 215 216 bcopy((char *)ð, ipbuf, sizeof(eth)); 217 sent += (ts - hlen); 218 if (!(ntohs(ip->ip_off) & IP_MF)) 219 break; 220 else if (!(ip->ip_off & htons(0x1fff))) 221 { 222 hlen = i + sizeof(*ip); 223 ip->ip_hl = (sizeof(*ip) + i) >> 2; 224 bcopy(optcpy, (char *)(ip + 1), i); 225 } 226 } 227 } 228 229 bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 230 return err; 231} 232 233 234/* 235 * send a tcp packet. 236 */ 237int send_tcp(nfd, mtu, ip, gwip) 238int nfd, mtu; 239ip_t *ip; 240struct in_addr gwip; 241{ 242 static tcp_seq iss = 2; 243 struct tcpiphdr *ti; 244 tcphdr_t *t; 245 int thlen, i, iplen, hlen; 246 u_32_t lbuf[20]; 247 248 iplen = ip->ip_len; 249 hlen = ip->ip_hl << 2; 250 t = (tcphdr_t *)((char *)ip + hlen); 251 ti = (struct tcpiphdr *)lbuf; 252 thlen = t->th_off << 2; 253 if (!thlen) 254 thlen = sizeof(tcphdr_t); 255 bzero((char *)ti, sizeof(*ti)); 256 ip->ip_p = IPPROTO_TCP; 257 ti->ti_pr = ip->ip_p; 258 ti->ti_src = ip->ip_src; 259 ti->ti_dst = ip->ip_dst; 260 bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen); 261 262 if (!ti->ti_win) 263 ti->ti_win = htons(4096); 264 iss += 63; 265 266 i = sizeof(struct tcpiphdr) / sizeof(long); 267 268 if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) && 269 (lbuf[i] != htonl(0x020405b4))) { 270 lbuf[i] = htonl(0x020405b4); 271 bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, 272 iplen - thlen - hlen); 273 thlen += 4; 274 } 275 ti->ti_off = thlen >> 2; 276 ti->ti_len = htons(thlen); 277 ip->ip_len = hlen + thlen; 278 ti->ti_sum = 0; 279 ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 280 281 bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen); 282 return send_ip(nfd, mtu, ip, gwip, 1); 283} 284 285 286/* 287 * send a udp packet. 288 */ 289int send_udp(nfd, mtu, ip, gwip) 290int nfd, mtu; 291ip_t *ip; 292struct in_addr gwip; 293{ 294 struct tcpiphdr *ti; 295 int thlen; 296 u_long lbuf[20]; 297 298 ti = (struct tcpiphdr *)lbuf; 299 bzero((char *)ti, sizeof(*ti)); 300 thlen = sizeof(udphdr_t); 301 ti->ti_pr = ip->ip_p; 302 ti->ti_src = ip->ip_src; 303 ti->ti_dst = ip->ip_dst; 304 bcopy((char *)ip + (ip->ip_hl << 2), 305 (char *)&ti->ti_sport, sizeof(udphdr_t)); 306 307 ti->ti_len = htons(thlen); 308 ip->ip_len = (ip->ip_hl << 2) + thlen; 309 ti->ti_sum = 0; 310 ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 311 312 bcopy((char *)&ti->ti_sport, 313 (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); 314 return send_ip(nfd, mtu, ip, gwip, 1); 315} 316 317 318/* 319 * send an icmp packet. 320 */ 321int send_icmp(nfd, mtu, ip, gwip) 322int nfd, mtu; 323ip_t *ip; 324struct in_addr gwip; 325{ 326 struct icmp *ic; 327 328 ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); 329 330 ic->icmp_cksum = 0; 331 ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 332 333 return send_ip(nfd, mtu, ip, gwip, 1); 334} 335 336 337int send_packet(nfd, mtu, ip, gwip) 338int nfd, mtu; 339ip_t *ip; 340struct in_addr gwip; 341{ 342 switch (ip->ip_p) 343 { 344 case IPPROTO_TCP : 345 return send_tcp(nfd, mtu, ip, gwip); 346 case IPPROTO_UDP : 347 return send_udp(nfd, mtu, ip, gwip); 348 case IPPROTO_ICMP : 349 return send_icmp(nfd, mtu, ip, gwip); 350 default : 351 return send_ip(nfd, mtu, ip, gwip, 1); 352 } 353} 354