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 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 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 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 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 ((t2->th_flags == 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 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 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