root/sbin/ipf/ipsend/ipsend.c
/*
 * ipsend.c (C) 1995-1998 Darren Reed
 *
 * See the IPFILTER.LICENCE file for details on licencing.
 */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <netinet/ip.h>
# include <netinet/ip_var.h>
#include "ipsend.h"
#include "ipf.h"
# include <netinet/udp_var.h>


extern  char    *optarg;
extern  int     optind;
extern  void    iplang(FILE *);

char    options[68];
int     opts;
char    default_device[] = "le0";


static  void    usage(char *);
static  void    do_icmp(ip_t *, char *);
void udpcksum(ip_t *, struct udphdr *, int);
int     main(int, char **);


static  void    usage(prog)
        char    *prog;
{
        fprintf(stderr, "Usage: %s [options] dest [flags]\n\
\toptions:\n\
\t\t-d\tdebug mode\n\
\t\t-i device\tSend out on this device\n\
\t\t-f fragflags\tcan set IP_MF or IP_DF\n\
\t\t-g gateway\tIP gateway to use if non-local dest.\n\
\t\t-I code,type[,gw[,dst[,src]]]\tSet ICMP protocol\n\
\t\t-m mtu\t\tfake MTU to use when sending out\n\
\t\t-P protocol\tSet protocol by name\n\
\t\t-s src\t\tsource address for IP packet\n\
\t\t-T\t\tSet TCP protocol\n\
\t\t-t port\t\tdestination port\n\
\t\t-U\t\tSet UDP protocol\n\
\t\t-v\tverbose mode\n\
\t\t-w <window>\tSet the TCP window size\n\
", prog);
        fprintf(stderr, "Usage: %s [-dv] -L <filename>\n\
\toptions:\n\
\t\t-d\tdebug mode\n\
\t\t-L filename\tUse IP language for sending packets\n\
\t\t-v\tverbose mode\n\
", prog);
        exit(1);
}


static
void do_icmp(ip_t *ip, char *args)
{
        struct  icmp    *ic;
        char    *s;

        ip->ip_p = IPPROTO_ICMP;
        ip->ip_len += sizeof(*ic);
        ic = (struct icmp *)(ip + 1);
        bzero((char *)ic, sizeof(*ic));
        if (!(s = strchr(args, ',')))
            {
                fprintf(stderr, "ICMP args missing: ,\n");
                return;
            }
        *s++ = '\0';
        ic->icmp_type = atoi(args);
        ic->icmp_code = atoi(s);
        if (ic->icmp_type == ICMP_REDIRECT && strchr(s, ','))
            {
                char    *t;

                t = strtok(s, ",");
                t = strtok(NULL, ",");
                if (resolve(t, (char *)&ic->icmp_gwaddr) == -1)
                    {
                        fprintf(stderr,"Cant resolve %s\n", t);
                        exit(2);
                    }
                if ((t = strtok(NULL, ",")))
                    {
                        if (resolve(t, (char *)&ic->icmp_ip.ip_dst) == -1)
                            {
                                fprintf(stderr,"Cant resolve %s\n", t);
                                exit(2);
                            }
                        if ((t = strtok(NULL, ",")))
                            {
                                if (resolve(t,
                                            (char *)&ic->icmp_ip.ip_src) == -1)
                                    {
                                        fprintf(stderr,"Cant resolve %s\n", t);
                                        exit(2);
                                    }
                            }
                    }
            }
}


int
send_packets(char *dev, int mtu, ip_t *ip, struct in_addr gwip)
{
        int wfd;

        wfd = initdevice(dev, 5);
        if (wfd == -1)
                return (-1);
        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 *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(int argc, char **argv)
{
        FILE    *langfile = NULL;
        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;
        char    *src = NULL, *dst, *s;
        int     mtu = 1500, olen = 0, c, nonl = 0;

        /*
         * 65535 is maximum packet size...you never know...
         */
        ip = (ip_t *)calloc(1, 65536);
        tcp = (tcphdr_t *)(ip + 1);
        udp = (udphdr_t *)tcp;
        ip->ip_len = sizeof(*ip);
        IP_HL_A(ip, sizeof(*ip) >> 2);

        while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) {
                switch (c)
                {
                case 'I' :
                        nonl++;
                        if (ip->ip_p)
                            {
                                fprintf(stderr, "Protocol already set: %d\n",
                                        ip->ip_p);
                                break;
                            }
                        do_icmp(ip, optarg);
                        break;
                case 'L' :
                        if (nonl) {
                                fprintf(stderr,
                                        "Incorrect usage of -L option.\n");
                                usage(name);
                        }
                        if (!strcmp(optarg, "-"))
                                langfile = stdin;
                        else if (!(langfile = fopen(optarg, "r"))) {
                                fprintf(stderr, "can't open file %s\n",
                                        optarg);
                                exit(1);
                        }
                        iplang(langfile);
                        return (0);
                case 'P' :
                    {
                        struct  protoent        *p;

                        nonl++;
                        if (ip->ip_p)
                            {
                                fprintf(stderr, "Protocol already set: %d\n",
                                        ip->ip_p);
                                break;
                            }
                        if ((p = getprotobyname(optarg)))
                                ip->ip_p = p->p_proto;
                        else
                                fprintf(stderr, "Unknown protocol: %s\n",
                                        optarg);
                        break;
                    }
                case 'T' :
                        nonl++;
                        if (ip->ip_p)
                            {
                                fprintf(stderr, "Protocol already set: %d\n",
                                        ip->ip_p);
                                break;
                            }
                        ip->ip_p = IPPROTO_TCP;
                        ip->ip_len += sizeof(tcphdr_t);
                        break;
                case 'U' :
                        nonl++;
                        if (ip->ip_p)
                            {
                                fprintf(stderr, "Protocol already set: %d\n",
                                        ip->ip_p);
                                break;
                            }
                        ip->ip_p = IPPROTO_UDP;
                        ip->ip_len += sizeof(udphdr_t);
                        break;
                case 'd' :
                        opts |= OPT_DEBUG;
                        break;
                case 'f' :
                        nonl++;
                        ip->ip_off = strtol(optarg, NULL, 0);
                        break;
                case 'g' :
                        nonl++;
                        gateway = optarg;
                        break;
                case 'i' :
                        nonl++;
                        dev = optarg;
                        break;
                case 'm' :
                        nonl++;
                        mtu = atoi(optarg);
                        if (mtu < 28)
                            {
                                fprintf(stderr, "mtu must be > 28\n");
                                exit(1);
                            }
                        break;
                case 'o' :
                        nonl++;
                        olen = buildopts(optarg, options, (IP_HL(ip) - 5) << 2);
                        break;
                case 's' :
                        nonl++;
                        src = optarg;
                        break;
                case 't' :
                        nonl++;
                        if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
                                tcp->th_dport = htons(atoi(optarg));
                        break;
                case 'v' :
                        opts |= OPT_VERBOSE;
                        break;
                case 'w' :
                        nonl++;
                        if (ip->ip_p == IPPROTO_TCP)
                                tcp->th_win = atoi(optarg);
                        else
                                fprintf(stderr, "set protocol to TCP first\n");
                        break;
                default :
                        fprintf(stderr, "Unknown option \"%c\"\n", c);
                        usage(name);
                }
        }

        if (argc - optind < 1)
                usage(name);
        dst = argv[optind++];

        if (!src)
            {
                gethostname(host, sizeof(host));
                src = host;
            }

        if (resolve(src, (char *)&ip->ip_src) == -1)
            {
                fprintf(stderr,"Cant resolve %s\n", src);
                exit(2);
            }

        if (resolve(dst, (char *)&ip->ip_dst) == -1)
            {
                fprintf(stderr,"Cant resolve %s\n", dst);
                exit(2);
            }

        if (!gateway)
                gwip = ip->ip_dst;
        else if (resolve(gateway, (char *)&gwip) == -1)
            {
                fprintf(stderr,"Cant resolve %s\n", gateway);
                exit(2);
            }

        if (olen)
            {
                int hlen;
                char *p;

                printf("Options: %d\n", olen);
                hlen = sizeof(*ip) + olen;
                IP_HL_A(ip, hlen >> 2);
                ip->ip_len += olen;
                p = (char *)malloc(65536);
                if (p == NULL)
                    {
                        fprintf(stderr, "malloc failed\n");
                        exit(2);
                    }

                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 *)(p + hlen);
                } else if (ip->ip_p == IPPROTO_UDP) {
                        udp = (udphdr_t *)(p + hlen);
                }
            }

        if (ip->ip_p == IPPROTO_TCP)
                for (s = argv[optind]; s && (c = *s); s++)
                        switch(c)
                        {
                        case 'S' : case 's' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_SYN);
                                break;
                        case 'A' : case 'a' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_ACK);
                                break;
                        case 'F' : case 'f' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_FIN);
                                break;
                        case 'R' : case 'r' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_RST);
                                break;
                        case 'P' : case 'p' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_PUSH);
                                break;
                        case 'U' : case 'u' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_URG);
                                break;
                        case 'E' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_ECE);
                                break;
                        case 'W' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_CWR);
                                break;
                        case 'e' :
                                __tcp_set_flags(tcp, __tcp_get_flags(tcp) | TH_AE);
                                break;
                        }

        if (!dev)
                dev = default_device;
        printf("Device:  %s\n", dev);
        printf("Source:  %s\n", inet_ntoa(ip->ip_src));
        printf("Dest:    %s\n", inet_ntoa(ip->ip_dst));
        printf("Gateway: %s\n", inet_ntoa(gwip));
        if (ip->ip_p == IPPROTO_TCP && __tcp_get_flags(tcp) != 0)
                printf("Flags:   %#x\n", __tcp_get_flags(tcp));
        printf("mtu:     %d\n", mtu);

        if (ip->ip_p == IPPROTO_UDP) {
                udp->uh_sum = 0;
                udpcksum(ip, udp, ip->ip_len - (IP_HL(ip) << 2));
        }
#ifdef  DOSOCKET
        if (ip->ip_p == IPPROTO_TCP && tcp->th_dport)
                return (do_socket(dev, mtu, ip, gwip));
#endif
        return (send_packets(dev, mtu, ip, gwip));
}