diff options
Diffstat (limited to 'contrib/ipfilter/ipsend/ipsend.c')
-rw-r--r-- | contrib/ipfilter/ipsend/ipsend.c | 83 |
1 files changed, 67 insertions, 16 deletions
diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c index 8c9be57..80faef2 100644 --- a/contrib/ipfilter/ipsend/ipsend.c +++ b/contrib/ipfilter/ipsend/ipsend.c @@ -25,8 +25,10 @@ #include <arpa/inet.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <netinet/ip_var.h> #include <netinet/tcp.h> #include <netinet/udp.h> +#include <netinet/udp_var.h> #include <netinet/ip_icmp.h> #ifndef linux #include <netinet/ip_var.h> @@ -71,6 +73,7 @@ char default_device[] = "lan0"; static void usage __P((char *)); static void do_icmp __P((ip_t *, char *)); +void udpcksum(ip_t *, struct udphdr *, int); int main __P((int, char **)); @@ -170,6 +173,37 @@ struct in_addr gwip; return send_packet(wfd, mtu, ip, gwip); } +void +udpcksum(ip_t *ip, struct udphdr *udp, int len) +{ + union pseudoh { + struct hdr { + u_short len; + u_char ttl; + u_char proto; + u_32_t src; + u_32_t dst; + } h; + u_short w[6]; + } ph; + u_32_t temp32; + u_short cksum, *opts; + + ph.h.len = htons(len); + ph.h.ttl = 0; + ph.h.proto = IPPROTO_UDP; + ph.h.src = ip->ip_src.s_addr; + ph.h.dst = ip->ip_dst.s_addr; + temp32 = 0; + opts = &ph.w[0]; + temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5]; + temp32 = (temp32 >> 16) + (temp32 & 65535); + temp32 += (temp32 >> 16); + udp->uh_sum = temp32 & 65535; + udp->uh_sum = chksum((u_short *)udp, len); + if (udp->uh_sum == 0) + udp->uh_sum = 0xffff; +} int main(argc, argv) int argc; @@ -177,8 +211,10 @@ char **argv; { FILE *langfile = NULL; struct tcpiphdr *ti; + struct udpiphdr *ui; struct in_addr gwip; tcphdr_t *tcp; + udphdr_t *udp; ip_t *ip; char *name = argv[0], host[MAXHOSTNAMELEN + 1]; char *gateway = NULL, *dev = NULL; @@ -190,7 +226,10 @@ char **argv; */ ip = (ip_t *)calloc(1, 65536); ti = (struct tcpiphdr *)ip; + ui = (struct udpiphdr *)ip; tcp = (tcphdr_t *)&ti->ti_sport; + udp = (udphdr_t *)&ui->ui_sport; + ui->ui_ulen = htons(sizeof(*udp)); ip->ip_len = sizeof(*ip); ip->ip_hl = sizeof(*ip) >> 2; @@ -344,27 +383,35 @@ char **argv; exit(2); } + if (ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP) { + fprintf(stderr,"Unsupported protocol %d\n", ip->ip_p); + exit(2); + } + if (olen) { - caddr_t ipo = (caddr_t)ip; + int hlen; + char *p; printf("Options: %d\n", olen); - ti = (struct tcpiphdr *)malloc(olen + ip->ip_len); - if(!ti) + hlen = sizeof(*ip) + olen; + ip->ip_hl = hlen >> 2; + ip->ip_len += olen; + p = (char *)malloc(65536); + if(!p) { fprintf(stderr,"malloc failed\n"); exit(2); } - - bcopy((char *)ip, (char *)ti, sizeof(*ip)); - ip = (ip_t *)ti; - ip->ip_hl = (olen >> 2); - bcopy(options, (char *)(ip + 1), olen); - bcopy((char *)tcp, (char *)(ip + 1) + olen, sizeof(*tcp)); - ip->ip_len += olen; - bcopy((char *)ip, (char *)ipo, ip->ip_len); - ip = (ip_t *)ipo; - tcp = (tcphdr_t *)((char *)(ip + 1) + olen); + bcopy(ip, p, sizeof(*ip)); + bcopy(options, p + sizeof(*ip), olen); + bcopy(ip + 1, p + hlen, ip->ip_len - hlen); + ip = (ip_t *)p; + if (ip->ip_p == IPPROTO_TCP) { + tcp = (tcphdr_t *)((char *)ip + hlen); + } else { + udp = (udphdr_t *)((char *)ip + hlen); + } } if (ip->ip_p == IPPROTO_TCP) @@ -401,9 +448,13 @@ char **argv; printf("Flags: %#x\n", tcp->th_flags); printf("mtu: %d\n", mtu); + if (ip->ip_p == IPPROTO_UDP) { + udp->uh_sum = 0; + udpcksum(ip, udp, (ip->ip_len) - (ip->ip_hl << 2)); + } #ifdef DOSOCKET - if (tcp->th_dport) - return do_socket(dev, mtu, ti, gwip); + if (ip->ip_p == IPPROTO_TCP && tcp->th_dport) + return do_socket(dev, mtu, (struct tcpiphdr *)ip, gwip); #endif - return send_packets(dev, mtu, (ip_t *)ti, gwip); + return send_packets(dev, mtu, ip, gwip); } |