ip.c revision 31183
1164190Sjkoshy/* 2164190Sjkoshy * ip.c (C) 1995-1997 Darren Reed 3164190Sjkoshy * 4164190Sjkoshy * Redistribution and use in source and binary forms are permitted 5164190Sjkoshy * provided that this notice is preserved and due credit is given 6164190Sjkoshy * to the original author and the contributors. 7164190Sjkoshy */ 8164190Sjkoshy#if !defined(lint) 9164190Sjkoshystatic const char sccsid[] = "%W% %G% (C)1995"; 10164190Sjkoshystatic const char rcsid[] = "@(#)$Id: ip.c,v 2.0.2.11 1997/10/23 11:42:44 darrenr Exp $"; 11164190Sjkoshy#endif 12164190Sjkoshy#include <errno.h> 13164190Sjkoshy#include <stdio.h> 14164190Sjkoshy#include <stdlib.h> 15164190Sjkoshy#include <unistd.h> 16164190Sjkoshy#include <string.h> 17164190Sjkoshy#include <sys/types.h> 18164190Sjkoshy#include <netinet/in_systm.h> 19164190Sjkoshy#include <sys/socket.h> 20164190Sjkoshy#include <net/if.h> 21164190Sjkoshy#include <netinet/in.h> 22164190Sjkoshy#include <netinet/ip.h> 23164190Sjkoshy#include <netinet/tcp.h> 24164190Sjkoshy#include <netinet/udp.h> 25164190Sjkoshy#include <netinet/ip_icmp.h> 26164190Sjkoshy#include <sys/param.h> 27164190Sjkoshy#ifndef linux 28164190Sjkoshy# include <netinet/if_ether.h> 29164190Sjkoshy# include <netinet/ip_var.h> 30164190Sjkoshy# if __FreeBSD_version >= 300000 31164190Sjkoshy# include <net/if_var.h> 32164190Sjkoshy# endif 33164190Sjkoshy#endif 34164190Sjkoshy#include "ipsend.h" 35164190Sjkoshy 36164190Sjkoshy 37164190Sjkoshystatic char *ipbuf = NULL, *ethbuf = NULL; 38164190Sjkoshy 39164190Sjkoshy 40164190Sjkoshyu_short chksum(buf,len) 41164190Sjkoshyu_short *buf; 42164190Sjkoshyint len; 43164190Sjkoshy{ 44164190Sjkoshy u_long sum = 0; 45164190Sjkoshy int nwords = len >> 1; 46164190Sjkoshy 47164190Sjkoshy for(; nwords > 0; nwords--) 48164190Sjkoshy sum += *buf++; 49164190Sjkoshy sum = (sum>>16) + (sum & 0xffff); 50164190Sjkoshy sum += (sum >>16); 51164190Sjkoshy return (~sum); 52164190Sjkoshy} 53164190Sjkoshy 54164190Sjkoshy 55164190Sjkoshyint send_ether(nfd, buf, len, gwip) 56164190Sjkoshyint nfd, len; 57164190Sjkoshychar *buf; 58struct in_addr gwip; 59{ 60 static struct in_addr last_gw; 61 static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 62 ether_header_t *eh; 63 char *s; 64 int err; 65 66 if (!ethbuf) 67 ethbuf = (char *)calloc(1, 65536+1024); 68 s = ethbuf; 69 eh = (ether_header_t *)s; 70 71 bcopy((char *)buf, s + sizeof(*eh), len); 72 if (gwip.s_addr == last_gw.s_addr) 73 bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 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; 95 static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 96 static u_short id = 0; 97 ether_header_t *eh; 98 ip_t ipsv; 99 int err; 100 101 if (!ipbuf) 102 ipbuf = (char *)malloc(65536); 103 eh = (ether_header_t *)ipbuf; 104 105 bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); 106 if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 107 bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 108 else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 109 { 110 perror("arp"); 111 return -2; 112 } 113 bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); 114 eh->ether_type = htons(ETHERTYPE_IP); 115 116 bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 117 last_gw.s_addr = gwip.s_addr; 118 ip->ip_len = htons(ip->ip_len); 119 ip->ip_off = htons(ip->ip_off); 120 if (!(frag & 2)) { 121 if (!ip->ip_v) 122 ip->ip_v = IPVERSION; 123 if (!ip->ip_id) 124 ip->ip_id = htons(id++); 125 if (!ip->ip_ttl) 126 ip->ip_ttl = 60; 127 } 128 129 if (!frag || (sizeof(*eh) + ntohs(ip->ip_len) < mtu)) 130 { 131 ip->ip_sum = 0; 132 ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); 133 134 bcopy((char *)ip, ipbuf + sizeof(*eh), ntohs(ip->ip_len)); 135 err = sendip(nfd, ipbuf, sizeof(*eh) + ntohs(ip->ip_len)); 136 } 137 else 138 { 139 /* 140 * Actually, this is bogus because we're putting all IP 141 * options in every packet, which isn't always what should be 142 * done. Will do for now. 143 */ 144 ether_header_t eth; 145 char optcpy[48], ol; 146 char *s; 147 int i, iplen, sent = 0, ts, hlen, olen; 148 149 hlen = ip->ip_hl << 2; 150 if (mtu < (hlen + 8)) { 151 fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 152 mtu, hlen); 153 fprintf(stderr, "can't fragment data\n"); 154 return -2; 155 } 156 ol = (ip->ip_hl << 2) - sizeof(*ip); 157 for (i = 0, s = (char*)(ip + 1); ol > 0; ) 158 if (*s == IPOPT_EOL) { 159 optcpy[i++] = *s; 160 break; 161 } else if (*s == IPOPT_NOP) { 162 s++; 163 ol--; 164 } else 165 { 166 olen = (int)(*(u_char *)(s + 1)); 167 ol -= olen; 168 if (IPOPT_COPIED(*s)) 169 { 170 bcopy(s, optcpy + i, olen); 171 i += olen; 172 s += olen; 173 } 174 } 175 if (i) 176 { 177 /* 178 * pad out 179 */ 180 while ((i & 3) && (i & 3) != 3) 181 optcpy[i++] = IPOPT_NOP; 182 if ((i & 3) == 3) 183 optcpy[i++] = IPOPT_EOL; 184 } 185 186 bcopy((char *)eh, (char *)ð, sizeof(eth)); 187 s = (char *)ip + hlen; 188 iplen = ntohs(ip->ip_len) - hlen; 189 ip->ip_off |= htons(IP_MF); 190 191 while (1) 192 { 193 if ((sent + (mtu - hlen)) >= iplen) 194 { 195 ip->ip_off ^= htons(IP_MF); 196 ts = iplen - sent; 197 } 198 else 199 ts = (mtu - hlen); 200 ip->ip_off &= htons(0xe000); 201 ip->ip_off |= htons(sent >> 3); 202 ts += hlen; 203 ip->ip_len = htons(ts); 204 ip->ip_sum = 0; 205 ip->ip_sum = chksum((u_short *)ip, hlen); 206 bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 207 bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 208 err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 209 210 bcopy((char *)ð, ipbuf, sizeof(eth)); 211 sent += (ts - hlen); 212 if (!(ntohs(ip->ip_off) & IP_MF)) 213 break; 214 else if (!(ip->ip_off & htons(0x1fff))) 215 { 216 hlen = i + sizeof(*ip); 217 ip->ip_hl = (sizeof(*ip) + i) >> 2; 218 bcopy(optcpy, (char *)(ip + 1), i); 219 } 220 } 221 } 222 223 bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 224 return err; 225} 226 227 228/* 229 * send a tcp packet. 230 */ 231int send_tcp(nfd, mtu, ip, gwip) 232int nfd, mtu; 233ip_t *ip; 234struct in_addr gwip; 235{ 236 static tcp_seq iss = 2; 237 struct tcpiphdr *ti; 238 int thlen, i; 239 u_long lbuf[20]; 240 241 ti = (struct tcpiphdr *)lbuf; 242 bzero((char *)ti, sizeof(*ti)); 243 thlen = sizeof(tcphdr_t); 244 ip->ip_p = IPPROTO_TCP; 245 ti->ti_pr = ip->ip_p; 246 ti->ti_src = ip->ip_src; 247 ti->ti_dst = ip->ip_dst; 248 bcopy((char *)ip + (ip->ip_hl << 2), 249 (char *)&ti->ti_sport, sizeof(tcphdr_t)); 250 251 if (!ti->ti_win) 252 ti->ti_win = htons(4096); 253 if (!ti->ti_seq) 254 ti->ti_seq = htonl(iss); 255 iss += 64; 256 257 if ((ti->ti_flags == TH_SYN) && !ip->ip_off) 258 { 259 ip = (ip_t *)realloc((char *)ip, ntohs(ip->ip_len) + 4); 260 i = sizeof(struct tcpiphdr) / sizeof(long); 261 lbuf[i] = htonl(0x020405b4); 262 bcopy((char *)(lbuf + i), (char*)ip + ntohs(ip->ip_len), 263 sizeof(u_long)); 264 thlen += 4; 265 } 266 if (!ti->ti_off) 267 ti->ti_off = thlen >> 2; 268 ti->ti_len = htons(thlen); 269 ip->ip_len = (ip->ip_hl << 2) + thlen; 270 ti->ti_sum = 0; 271 ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 272 273 bcopy((char *)&ti->ti_sport, 274 (char *)ip + (ip->ip_hl << 2), thlen); 275 return send_ip(nfd, mtu, ip, gwip, 1); 276} 277 278 279/* 280 * send a udp packet. 281 */ 282int send_udp(nfd, mtu, ip, gwip) 283int nfd, mtu; 284ip_t *ip; 285struct in_addr gwip; 286{ 287 struct tcpiphdr *ti; 288 int thlen; 289 u_long lbuf[20]; 290 291 ti = (struct tcpiphdr *)lbuf; 292 bzero((char *)ti, sizeof(*ti)); 293 thlen = sizeof(udphdr_t); 294 ti->ti_pr = ip->ip_p; 295 ti->ti_src = ip->ip_src; 296 ti->ti_dst = ip->ip_dst; 297 bcopy((char *)ip + (ip->ip_hl << 2), 298 (char *)&ti->ti_sport, sizeof(udphdr_t)); 299 300 ti->ti_len = htons(thlen); 301 ip->ip_len = (ip->ip_hl << 2) + thlen; 302 ti->ti_sum = 0; 303 ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 304 305 bcopy((char *)&ti->ti_sport, 306 (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); 307 return send_ip(nfd, mtu, ip, gwip, 1); 308} 309 310 311/* 312 * send an icmp packet. 313 */ 314int send_icmp(nfd, mtu, ip, gwip) 315int nfd, mtu; 316ip_t *ip; 317struct in_addr gwip; 318{ 319 struct icmp *ic; 320 321 ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); 322 323 ic->icmp_cksum = 0; 324 ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 325 326 return send_ip(nfd, mtu, ip, gwip, 1); 327} 328 329 330int send_packet(nfd, mtu, ip, gwip) 331int nfd, mtu; 332ip_t *ip; 333struct 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