1 /*
2  * mod_ip_opt.c
3  *
4  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5  *
6  * $Id$
7  */
8 
9 #include "config.h"
10 #include "defines.h"
11 #include "common.h"
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "pkt.h"
18 #include "mod.h"
19 #include "iputil.h"
20 
21 void *
ip_opt_close(void * d)22 ip_opt_close(void *d)
23 {
24     if (d != NULL)
25         free(d);
26     return (NULL);
27 }
28 
29 void *
ip_opt_open(int argc,char * argv[])30 ip_opt_open(int argc, char *argv[])
31 {
32     struct ip_opt *opt;
33     struct addr addr;
34     int i, j;
35 
36     if (argc < 4)
37         return (NULL);
38 
39     if ((opt = calloc(1, sizeof(*opt))) == NULL)
40         return (NULL);
41 
42     if (strcasecmp(argv[1], "lsrr") == 0) {
43         opt->opt_type = IP_OPT_LSRR;
44     } else if (strcasecmp(argv[1], "ssrr") == 0) {
45         opt->opt_type = IP_OPT_SSRR;
46     } else if (strcasecmp(argv[1], "raw") == 0) {
47         if (raw_ip_opt_parse(argc - 2, &argv[2], &opt->opt_type, &opt->opt_len,
48                     &opt->opt_data.data8[0], sizeof(opt->opt_data.data8)) != 0)
49             return (ip_opt_close(opt));
50         return opt;
51     } else
52         return (ip_opt_close(opt));
53 
54     if ((i = atoi(argv[2])) < 4 || i > 0xff) {
55         warn("<ptr> must be >= 4, and should be a multiple of 4");
56         return (ip_opt_close(opt));
57     }
58     opt->opt_data.rr.ptr = i;
59 
60     for (i = 3, j = 0; i < argc && j < 9; i++, j++) {
61         if (addr_aton(argv[i], &addr) < 0) {
62             return (ip_opt_close(opt));
63         }
64         opt->opt_data.rr.iplist[j] = addr.addr_ip;
65     }
66     opt->opt_len = IP_OPT_LEN + 1 + (IP_ADDR_LEN * j);
67 
68     return (opt);
69 }
70 
71 int
ip_opt_apply(void * d,struct pktq * pktq)72 ip_opt_apply(void *d, struct pktq *pktq)
73 {
74     struct ip_opt *opt = (struct ip_opt *)d;
75     struct pkt *pkt;
76     size_t len;
77 
78     TAILQ_FOREACH(pkt, pktq, pkt_next) {
79         uint16_t eth_type = htons(pkt->pkt_eth->eth_type);
80 
81         if (eth_type == ETH_TYPE_IP) {
82         len = ip_add_option(pkt->pkt_ip, PKT_BUF_LEN - ETH_HDR_LEN,
83             IP_PROTO_IP, opt, opt->opt_len);
84 
85         if (len > 0) {
86             pkt->pkt_end += len;
87             pkt_decorate(pkt);
88             ip_checksum(pkt->pkt_ip,
89                 pkt->pkt_end - pkt->pkt_eth_data);
90         }
91     }
92     }
93     return (0);
94 }
95 
96 struct mod mod_ip_opt = {
97     "ip_opt",                    /* name */
98     "ip_opt [lsrr|ssrr <ptr> <ip-addr> ...] | [raw <byte stream>]",        /* usage */
99     ip_opt_open,                    /* open */
100     ip_opt_apply,                    /* apply */
101     ip_opt_close                    /* close */
102 };
103