ip.c revision 53024
122514Sdarrenr/* 253024Sguido * ip.c (C) 1995-1998 Darren Reed 322514Sdarrenr * 431183Speter * Redistribution and use in source and binary forms are permitted 531183Speter * provided that this notice is preserved and due credit is given 631183Speter * to the original author and the contributors. 722514Sdarrenr */ 831183Speter#if !defined(lint) 931183Speterstatic const char sccsid[] = "%W% %G% (C)1995"; 1053024Sguidostatic const char rcsid[] = "@(#)$Id: ip.c,v 2.1 1999/08/04 17:31:04 darrenr Exp $"; 1122514Sdarrenr#endif 1222514Sdarrenr#include <errno.h> 1322514Sdarrenr#include <stdio.h> 1422514Sdarrenr#include <stdlib.h> 1522514Sdarrenr#include <unistd.h> 1622514Sdarrenr#include <string.h> 1722514Sdarrenr#include <sys/types.h> 1822514Sdarrenr#include <netinet/in_systm.h> 1922514Sdarrenr#include <sys/socket.h> 2022514Sdarrenr#include <net/if.h> 2122514Sdarrenr#include <netinet/in.h> 2222514Sdarrenr#include <netinet/ip.h> 2322514Sdarrenr#include <netinet/tcp.h> 2422514Sdarrenr#include <netinet/udp.h> 2522514Sdarrenr#include <netinet/ip_icmp.h> 2631183Speter#include <sys/param.h> 2722514Sdarrenr#ifndef linux 2831183Speter# include <netinet/if_ether.h> 2931183Speter# include <netinet/ip_var.h> 3031183Speter# if __FreeBSD_version >= 300000 3131183Speter# include <net/if_var.h> 3231183Speter# endif 3322514Sdarrenr#endif 3424583Sdarrenr#include "ipsend.h" 3522514Sdarrenr 3622514Sdarrenr 3722514Sdarrenrstatic char *ipbuf = NULL, *ethbuf = NULL; 3822514Sdarrenr 3922514Sdarrenr 4022514Sdarrenru_short chksum(buf,len) 4122514Sdarrenru_short *buf; 4222514Sdarrenrint len; 4322514Sdarrenr{ 4422514Sdarrenr u_long sum = 0; 4522514Sdarrenr int nwords = len >> 1; 4622514Sdarrenr 4722514Sdarrenr for(; nwords > 0; nwords--) 4822514Sdarrenr sum += *buf++; 4922514Sdarrenr sum = (sum>>16) + (sum & 0xffff); 5022514Sdarrenr sum += (sum >>16); 5122514Sdarrenr return (~sum); 5222514Sdarrenr} 5322514Sdarrenr 5422514Sdarrenr 5522514Sdarrenrint send_ether(nfd, buf, len, gwip) 5622514Sdarrenrint nfd, len; 5722514Sdarrenrchar *buf; 5822514Sdarrenrstruct in_addr gwip; 5922514Sdarrenr{ 6022514Sdarrenr static struct in_addr last_gw; 6122514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 6222514Sdarrenr ether_header_t *eh; 6322514Sdarrenr char *s; 6422514Sdarrenr int err; 6522514Sdarrenr 6622514Sdarrenr if (!ethbuf) 6722514Sdarrenr ethbuf = (char *)calloc(1, 65536+1024); 6822514Sdarrenr s = ethbuf; 6922514Sdarrenr eh = (ether_header_t *)s; 7022514Sdarrenr 7122514Sdarrenr bcopy((char *)buf, s + sizeof(*eh), len); 7222514Sdarrenr if (gwip.s_addr == last_gw.s_addr) 7331183Speter bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 7431183Speter else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 7522514Sdarrenr { 7622514Sdarrenr perror("arp"); 7722514Sdarrenr return -2; 7822514Sdarrenr } 7931183Speter eh->ether_type = htons(ETHERTYPE_IP); 8022514Sdarrenr last_gw.s_addr = gwip.s_addr; 8122514Sdarrenr err = sendip(nfd, s, sizeof(*eh) + len); 8222514Sdarrenr return err; 8322514Sdarrenr} 8422514Sdarrenr 8522514Sdarrenr 8622514Sdarrenr/* 8722514Sdarrenr */ 8822514Sdarrenrint send_ip(nfd, mtu, ip, gwip, frag) 8922514Sdarrenrint nfd, mtu; 9022514Sdarrenrip_t *ip; 9122514Sdarrenrstruct in_addr gwip; 9222514Sdarrenrint frag; 9322514Sdarrenr{ 9422514Sdarrenr static struct in_addr last_gw; 9522514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 9622514Sdarrenr static u_short id = 0; 9722514Sdarrenr ether_header_t *eh; 9822514Sdarrenr ip_t ipsv; 9934739Speter int err, iplen; 10022514Sdarrenr 10122514Sdarrenr if (!ipbuf) 10222514Sdarrenr ipbuf = (char *)malloc(65536); 10322514Sdarrenr eh = (ether_header_t *)ipbuf; 10422514Sdarrenr 10531183Speter bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); 10622514Sdarrenr if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 10731183Speter bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 10831183Speter else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 10922514Sdarrenr { 11022514Sdarrenr perror("arp"); 11122514Sdarrenr return -2; 11222514Sdarrenr } 11331183Speter bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); 11431183Speter eh->ether_type = htons(ETHERTYPE_IP); 11522514Sdarrenr 11622514Sdarrenr bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 11722514Sdarrenr last_gw.s_addr = gwip.s_addr; 11834739Speter iplen = ip->ip_len; 11934739Speter ip->ip_len = htons(iplen); 12031183Speter if (!(frag & 2)) { 12131183Speter if (!ip->ip_v) 12231183Speter ip->ip_v = IPVERSION; 12331183Speter if (!ip->ip_id) 12431183Speter ip->ip_id = htons(id++); 12531183Speter if (!ip->ip_ttl) 12631183Speter ip->ip_ttl = 60; 12731183Speter } 12822514Sdarrenr 12934739Speter if (!frag || (sizeof(*eh) + iplen < mtu)) 13022514Sdarrenr { 13122514Sdarrenr ip->ip_sum = 0; 13224583Sdarrenr ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); 13322514Sdarrenr 13434739Speter bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); 13534739Speter err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); 13622514Sdarrenr } 13722514Sdarrenr else 13822514Sdarrenr { 13922514Sdarrenr /* 14022514Sdarrenr * Actually, this is bogus because we're putting all IP 14122514Sdarrenr * options in every packet, which isn't always what should be 14222514Sdarrenr * done. Will do for now. 14322514Sdarrenr */ 14422514Sdarrenr ether_header_t eth; 14522514Sdarrenr char optcpy[48], ol; 14622514Sdarrenr char *s; 14734739Speter int i, sent = 0, ts, hlen, olen; 14822514Sdarrenr 14922514Sdarrenr hlen = ip->ip_hl << 2; 15022514Sdarrenr if (mtu < (hlen + 8)) { 15122514Sdarrenr fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 15222514Sdarrenr mtu, hlen); 15322514Sdarrenr fprintf(stderr, "can't fragment data\n"); 15422514Sdarrenr return -2; 15522514Sdarrenr } 15622514Sdarrenr ol = (ip->ip_hl << 2) - sizeof(*ip); 15722514Sdarrenr for (i = 0, s = (char*)(ip + 1); ol > 0; ) 15822514Sdarrenr if (*s == IPOPT_EOL) { 15922514Sdarrenr optcpy[i++] = *s; 16022514Sdarrenr break; 16122514Sdarrenr } else if (*s == IPOPT_NOP) { 16222514Sdarrenr s++; 16322514Sdarrenr ol--; 16422514Sdarrenr } else 16522514Sdarrenr { 16622514Sdarrenr olen = (int)(*(u_char *)(s + 1)); 16722514Sdarrenr ol -= olen; 16822514Sdarrenr if (IPOPT_COPIED(*s)) 16922514Sdarrenr { 17022514Sdarrenr bcopy(s, optcpy + i, olen); 17122514Sdarrenr i += olen; 17222514Sdarrenr s += olen; 17322514Sdarrenr } 17422514Sdarrenr } 17522514Sdarrenr if (i) 17622514Sdarrenr { 17722514Sdarrenr /* 17822514Sdarrenr * pad out 17922514Sdarrenr */ 18022514Sdarrenr while ((i & 3) && (i & 3) != 3) 18122514Sdarrenr optcpy[i++] = IPOPT_NOP; 18222514Sdarrenr if ((i & 3) == 3) 18322514Sdarrenr optcpy[i++] = IPOPT_EOL; 18422514Sdarrenr } 18522514Sdarrenr 18622514Sdarrenr bcopy((char *)eh, (char *)ð, sizeof(eth)); 18722514Sdarrenr s = (char *)ip + hlen; 18822514Sdarrenr iplen = ntohs(ip->ip_len) - hlen; 18922514Sdarrenr ip->ip_off |= htons(IP_MF); 19022514Sdarrenr 19122514Sdarrenr while (1) 19222514Sdarrenr { 19322514Sdarrenr if ((sent + (mtu - hlen)) >= iplen) 19422514Sdarrenr { 19522514Sdarrenr ip->ip_off ^= htons(IP_MF); 19622514Sdarrenr ts = iplen - sent; 19722514Sdarrenr } 19822514Sdarrenr else 19922514Sdarrenr ts = (mtu - hlen); 20022514Sdarrenr ip->ip_off &= htons(0xe000); 20122514Sdarrenr ip->ip_off |= htons(sent >> 3); 20222514Sdarrenr ts += hlen; 20322514Sdarrenr ip->ip_len = htons(ts); 20422514Sdarrenr ip->ip_sum = 0; 20524583Sdarrenr ip->ip_sum = chksum((u_short *)ip, hlen); 20622514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 20722514Sdarrenr bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 20822514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 20922514Sdarrenr 21022514Sdarrenr bcopy((char *)ð, ipbuf, sizeof(eth)); 21122514Sdarrenr sent += (ts - hlen); 21222514Sdarrenr if (!(ntohs(ip->ip_off) & IP_MF)) 21322514Sdarrenr break; 21422514Sdarrenr else if (!(ip->ip_off & htons(0x1fff))) 21522514Sdarrenr { 21622514Sdarrenr hlen = i + sizeof(*ip); 21722514Sdarrenr ip->ip_hl = (sizeof(*ip) + i) >> 2; 21822514Sdarrenr bcopy(optcpy, (char *)(ip + 1), i); 21922514Sdarrenr } 22022514Sdarrenr } 22122514Sdarrenr } 22222514Sdarrenr 22322514Sdarrenr bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 22422514Sdarrenr return err; 22522514Sdarrenr} 22622514Sdarrenr 22722514Sdarrenr 22822514Sdarrenr/* 22922514Sdarrenr * send a tcp packet. 23022514Sdarrenr */ 23122514Sdarrenrint send_tcp(nfd, mtu, ip, gwip) 23222514Sdarrenrint nfd, mtu; 23322514Sdarrenrip_t *ip; 23422514Sdarrenrstruct in_addr gwip; 23522514Sdarrenr{ 23622514Sdarrenr static tcp_seq iss = 2; 23722514Sdarrenr struct tcpiphdr *ti; 23834739Speter tcphdr_t *t; 23934739Speter int thlen, i, iplen, hlen; 24034739Speter u_32_t lbuf[20]; 24122514Sdarrenr 24234739Speter iplen = ip->ip_len; 24334739Speter hlen = ip->ip_hl << 2; 24434739Speter t = (tcphdr_t *)((char *)ip + hlen); 24522514Sdarrenr ti = (struct tcpiphdr *)lbuf; 24634739Speter thlen = t->th_off << 2; 24734739Speter if (!thlen) 24834739Speter thlen = sizeof(tcphdr_t); 24922514Sdarrenr bzero((char *)ti, sizeof(*ti)); 25022514Sdarrenr ip->ip_p = IPPROTO_TCP; 25122514Sdarrenr ti->ti_pr = ip->ip_p; 25222514Sdarrenr ti->ti_src = ip->ip_src; 25322514Sdarrenr ti->ti_dst = ip->ip_dst; 25434739Speter bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen); 25522514Sdarrenr 25622514Sdarrenr if (!ti->ti_win) 25722514Sdarrenr ti->ti_win = htons(4096); 25834739Speter iss += 63; 25922514Sdarrenr 26034739Speter i = sizeof(struct tcpiphdr) / sizeof(long); 26134739Speter 26237074Speter if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) && 26334739Speter (lbuf[i] != htonl(0x020405b4))) { 26422514Sdarrenr lbuf[i] = htonl(0x020405b4); 26534739Speter bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, 26634739Speter iplen - thlen - hlen); 26722514Sdarrenr thlen += 4; 26822514Sdarrenr } 26934739Speter ti->ti_off = thlen >> 2; 27022514Sdarrenr ti->ti_len = htons(thlen); 27134739Speter ip->ip_len = hlen + thlen; 27222514Sdarrenr ti->ti_sum = 0; 27324583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 27422514Sdarrenr 27534739Speter bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen); 27622514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 27722514Sdarrenr} 27822514Sdarrenr 27922514Sdarrenr 28022514Sdarrenr/* 28122514Sdarrenr * send a udp packet. 28222514Sdarrenr */ 28322514Sdarrenrint send_udp(nfd, mtu, ip, gwip) 28422514Sdarrenrint nfd, mtu; 28522514Sdarrenrip_t *ip; 28622514Sdarrenrstruct in_addr gwip; 28722514Sdarrenr{ 28822514Sdarrenr struct tcpiphdr *ti; 28922514Sdarrenr int thlen; 29022514Sdarrenr u_long lbuf[20]; 29122514Sdarrenr 29222514Sdarrenr ti = (struct tcpiphdr *)lbuf; 29322514Sdarrenr bzero((char *)ti, sizeof(*ti)); 29422514Sdarrenr thlen = sizeof(udphdr_t); 29522514Sdarrenr ti->ti_pr = ip->ip_p; 29622514Sdarrenr ti->ti_src = ip->ip_src; 29722514Sdarrenr ti->ti_dst = ip->ip_dst; 29822514Sdarrenr bcopy((char *)ip + (ip->ip_hl << 2), 29922514Sdarrenr (char *)&ti->ti_sport, sizeof(udphdr_t)); 30022514Sdarrenr 30122514Sdarrenr ti->ti_len = htons(thlen); 30222514Sdarrenr ip->ip_len = (ip->ip_hl << 2) + thlen; 30322514Sdarrenr ti->ti_sum = 0; 30424583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 30522514Sdarrenr 30622514Sdarrenr bcopy((char *)&ti->ti_sport, 30722514Sdarrenr (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); 30822514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 30922514Sdarrenr} 31022514Sdarrenr 31122514Sdarrenr 31222514Sdarrenr/* 31322514Sdarrenr * send an icmp packet. 31422514Sdarrenr */ 31522514Sdarrenrint send_icmp(nfd, mtu, ip, gwip) 31622514Sdarrenrint nfd, mtu; 31722514Sdarrenrip_t *ip; 31822514Sdarrenrstruct in_addr gwip; 31922514Sdarrenr{ 32022514Sdarrenr struct icmp *ic; 32122514Sdarrenr 32222514Sdarrenr ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); 32322514Sdarrenr 32422514Sdarrenr ic->icmp_cksum = 0; 32524583Sdarrenr ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 32622514Sdarrenr 32722514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 32822514Sdarrenr} 32922514Sdarrenr 33022514Sdarrenr 33122514Sdarrenrint send_packet(nfd, mtu, ip, gwip) 33222514Sdarrenrint nfd, mtu; 33322514Sdarrenrip_t *ip; 33422514Sdarrenrstruct in_addr gwip; 33522514Sdarrenr{ 33622514Sdarrenr switch (ip->ip_p) 33722514Sdarrenr { 33822514Sdarrenr case IPPROTO_TCP : 33922514Sdarrenr return send_tcp(nfd, mtu, ip, gwip); 34022514Sdarrenr case IPPROTO_UDP : 34122514Sdarrenr return send_udp(nfd, mtu, ip, gwip); 34222514Sdarrenr case IPPROTO_ICMP : 34322514Sdarrenr return send_icmp(nfd, mtu, ip, gwip); 34422514Sdarrenr default : 34522514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 34622514Sdarrenr } 34722514Sdarrenr} 348