1 /*
2  * Regression test for bugs in ipv4 ip_offset and h_len handling, such as
3  *   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=418975
4  *
5  * Copyright (c) 2009 Sam Roberts <sroberts@wurldtech.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 #if (HAVE_CONFIG_H)
31 #include "../include/config.h"
32 #endif
33 #include "./libnet_test.h"
34 
35 #include <assert.h>
36 
assert_eq_(long have,long want,const char * file,int line)37 static void assert_eq_(long have, long want, const char* file, int line) {
38     if(have != want) {
39         printf("%s:%d: fail - have %ld want %ld\n", file, line, have, want);
40         abort();
41     }
42 }
43 #define assert_eq(have, want) assert_eq_(have, want, __FILE__, __LINE__)
44 
45 
print_pblocks(libnet_t * l)46 static void print_pblocks(libnet_t* l)
47 {
48     libnet_pblock_t* p = l->protocol_blocks;
49 
50     while(p) {
51         printf("  tag %2d flags %d type %20s/%#x buf %p b_len %2u h_len %2u copied %2u\n",
52                 p->ptag, p->flags,
53                 libnet_diag_dump_pblock_type(p->type), p->type,
54                 p->buf, p->b_len, p->h_len, p->copied);
55         p = p->next;
56     }
57     printf("  link_offset %d aligner %d total_size %u nblocks %d\n",
58             l->link_offset, l->aligner, l->total_size, l->n_pblocks);
59 
60 }
61 
ptag_error(libnet_t * l,int ptag)62 static void ptag_error(libnet_t* l, int ptag)
63 {
64     if(ptag <= 0) {
65         printf("error: %s\n", libnet_geterror(l));
66     }
67     assert(ptag > 0);
68 }
69 
build_ipo(libnet_t * l,libnet_ptag_t ptag,int payload_s)70 static int build_ipo(libnet_t* l, libnet_ptag_t ptag, int payload_s)
71 {
72     uint8_t* payload = malloc(payload_s);
73     assert(payload);
74     memset(payload, '\x88', payload_s);
75 
76     ptag = libnet_build_ipv4_options(payload, payload_s, l, ptag);
77 
78     ptag_error(l, ptag);
79 
80     free(payload);
81 
82     return ptag;
83 }
84 
build_ipv4(libnet_t * l,libnet_ptag_t ptag,int payload_s,int ip_len)85 static int build_ipv4(libnet_t* l, libnet_ptag_t ptag, int payload_s, int ip_len)
86 {
87     u_long src_ip = 0xf101f1f1;
88     u_long dst_ip = 0xf102f1f1;
89     uint8_t* payload = malloc(payload_s);
90     assert(payload);
91     memset(payload, '\x99', payload_s);
92 
93     if(!ip_len) {
94         ip_len = LIBNET_IPV4_H + payload_s;
95     }
96 
97     ptag = libnet_build_ipv4(
98         ip_len,                                     /* length */
99         0,                                          /* TOS */
100         0xbbbb,                                     /* IP ID */
101         0,                                          /* IP Frag */
102         0xcc,                                       /* TTL */
103         IPPROTO_UDP,                                /* protocol */
104         0,                                          /* checksum */
105         src_ip,                                     /* source IP */
106         dst_ip,                                     /* destination IP */
107         payload_s ? payload : NULL,                 /* payload */
108         payload_s,                                  /* payload size */
109         l,                                          /* libnet handle */
110         ptag);                                      /* libnet id */
111 
112     ptag_error(l, ptag);
113 
114     free(payload);
115 
116     return ptag;
117 }
118 
build_ethernet(libnet_t * l,libnet_ptag_t ptag)119 static int build_ethernet(libnet_t* l, libnet_ptag_t ptag)
120 {
121     uint8_t enet_src[6] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
122     uint8_t enet_dst[6] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
123 
124     ptag = libnet_build_ethernet(
125         enet_dst,                                   /* ethernet destination */
126         enet_src,                                   /* ethernet source */
127         ETHERTYPE_IP,                               /* protocol type */
128         NULL,                                       /* payload */
129         0,                                          /* payload size */
130         l,                                          /* libnet handle */
131         ptag);                                      /* libnet id */
132 
133     ptag_error(l, ptag);
134 
135     return ptag;
136 }
137 
138 static
assert_lengths(libnet_t * l,int ip_len,int ip_ihl,int payload_s)139 void assert_lengths(libnet_t* l, int ip_len, int ip_ihl, int payload_s)
140 {
141     uint8_t* pkt1 = NULL;
142     uint32_t pkt1_sz = 0;
143     struct libnet_ipv4_hdr* h1;
144     uint8_t* payload = NULL;
145 
146 
147     int r = libnet_pblock_coalesce(l, &pkt1, &pkt1_sz);
148     assert(r >= 0);
149 
150     print_pblocks(l);
151 
152     libnet_diag_dump_hex(pkt1, 14, 1, stdout);
153     libnet_diag_dump_hex(pkt1+14, pkt1_sz-14, 1, stdout);
154 
155     /* check ip IHL value, total ip pkt length, and options value */
156     h1 = (struct libnet_ipv4_hdr*) (pkt1+14);
157     assert_eq(h1->ip_hl, ip_ihl);
158     assert_eq(ntohs(h1->ip_len), ip_len);
159 
160     payload = ((uint8_t*) h1) + ip_ihl * 4;
161     if(payload_s > 0) {
162         assert(payload[0] == (uint8_t)'\x99');
163         assert(payload[payload_s-1] == (uint8_t)'\x99');
164     }
165 }
166 
167 int
main(int argc,char * argv[])168 main(int argc, char *argv[])
169 {
170     libnet_t *l;
171     char *device = "eth0";
172     char errbuf[LIBNET_ERRBUF_SIZE];
173     libnet_ptag_t ipo_ptag = 0;
174     libnet_ptag_t ip_ptag = 0;
175     libnet_ptag_t eth_ptag = 0;
176     int ip_len = 0;
177 
178     l = libnet_init( LIBNET_LINK, device, errbuf);
179 
180     assert(l);
181 
182     printf("Packet: options=4, payload=0\n");
183 
184     ip_len = 20 + 4 + 0; /* ip + options + payload */
185     ipo_ptag = build_ipo(l, ipo_ptag, 4);
186     ip_ptag = build_ipv4(l, ip_ptag, 0, 24);
187     eth_ptag = build_ethernet(l, eth_ptag);
188 
189     assert_lengths(l, 24, 6, 0);
190 
191     ipo_ptag = ip_ptag = eth_ptag = 0;
192 
193     libnet_clear_packet(l);
194 
195     printf("Packet: options=3, payload=1\n");
196 
197     ip_len = 20 + 4 + 1; /* ip + options + payload */
198     ipo_ptag = build_ipo(l, ipo_ptag, 3);
199     ip_ptag = build_ipv4(l, ip_ptag, 1, 25);
200     eth_ptag = build_ethernet(l, eth_ptag);
201 
202     assert_lengths(l, 25, 6, 1);
203 
204     ipo_ptag = ip_ptag = eth_ptag = 0;
205 
206     libnet_clear_packet(l);
207 
208     printf("Packet: options=3, payload=1\n");
209 
210     ip_len = 20 + 4 + 1; /* ip + options + payload */
211     ipo_ptag = build_ipo(l, ipo_ptag, 3);
212     ip_ptag = build_ipv4(l, ip_ptag, 1, ip_len);
213     eth_ptag = build_ethernet(l, eth_ptag);
214 
215     assert_lengths(l, 25, 6, 1);
216 
217     printf("... modify -> options=40\n");
218 
219     ip_len = 20 + 40 + 1; /* ip + options + payload */
220     ipo_ptag = build_ipo(l, ipo_ptag, 40);
221 
222     assert_lengths(l, ip_len, 15, 1);
223 
224     printf("... modify -> options=0\n");
225 
226     ip_len = 20 + 0 + 1; /* ip + options + payload */
227     ipo_ptag = build_ipo(l, ipo_ptag, 0);
228 
229     assert_lengths(l, ip_len, 5, 1);
230 
231     printf("... modify -> options=5\n");
232 
233     ip_len = 20 + 8 + 1; /* ip + options + payload */
234     ipo_ptag = build_ipo(l, ipo_ptag, 5);
235 
236     assert_lengths(l, ip_len, 7, 1);
237 
238     printf("... modify -> ip_payload=5\n");
239 
240     ip_len = 20 + 8 + 5; /* ip + options + payload */
241     ip_ptag = build_ipv4(l, ip_ptag, 5, ip_len);
242 
243     assert_lengths(l, ip_len, 7, 1);
244 
245     ipo_ptag = ip_ptag = eth_ptag = 0;
246 
247     libnet_clear_packet(l);
248 
249 
250     return (EXIT_SUCCESS);
251 }
252 
253