blob: 70825eafdb27bdc8fb13555ba894cd211cc9d5ca [file] [log] [blame]
Jakub Grajciare74c04f2021-01-04 11:28:33 +01001/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2017 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
16 */
17
18#include <stdint.h>
19#include <net/if.h>
20#include <sys/types.h>
21#include <fcntl.h>
22#include <sys/ioctl.h>
23#include <sys/socket.h>
24#include <sys/un.h>
25#include <sys/uio.h>
26#include <sys/mman.h>
27#include <sys/prctl.h>
28#include <inttypes.h>
29#include <string.h>
30#include <stdio.h>
31#include <netdb.h>
32#include <linux/ip.h>
33#include <linux/icmp.h>
34#include <arpa/inet.h>
35#include <stdlib.h>
36#include <netinet/if_ether.h>
37#include <net/if_arp.h>
38#include <asm/byteorder.h>
39#include <byteswap.h>
40#include <assert.h>
41
42#include <icmp_proto.h>
43
44static uint16_t
45cksum (void *addr, ssize_t len)
46{
47 char *data = (char *) addr;
48
49 uint32_t acc = 0xffff;
50
51 ssize_t i;
52 for (i = 0; (i + 1) < len; i += 2)
53 {
54 uint16_t word;
55 memcpy (&word, data + i, 2);
56 acc += ntohs (word);
57 if (acc > 0xffff)
58 acc -= 0xffff;
59 }
60
61 if (len & 1)
62 {
63 uint16_t word = 0;
64 memcpy (&word, data + len - 1, 1);
65 acc += ntohs (word);
66 if (acc > 0xffff)
67 acc -= 0xffff;
68 }
69 return htons (~acc);
70}
71
72int
73print_packet (void *pck)
74{
75 if (pck == NULL)
76 {
77 printf ("ICMP_PROTO: no data\n");
78 return -1;
79 }
80 struct iphdr *ip;
81 struct icmphdr *icmp;
82 ip = (struct iphdr *) pck;
83 icmp = (struct icmphdr *) (pck + sizeof (struct iphdr));
84 printf ("received packet:\n");
85 printf ("\tiphdr:\n");
86 printf ("\t\tihl: %u\n\t\tversion: %u\n\t\tlen: %u\n\t\tid: %u\n", ip->ihl,
87 ip->version, __bswap_16 (ip->tot_len), ip->id);
88 printf ("\t\tprotocol: %u\n", ip->protocol);
89
90 printf ("\t\tsaddr: ");
91 int i;
92 for (i = 0; i < 4; i++)
93 {
94 printf ("%u.", ((uint8_t *) &ip->saddr)[i]);
95 }
96 printf ("\n");
97
98 printf ("\t\tdaddr: ");
99 for (i = 0; i < 4; i++)
100 {
101 printf ("%u.", ((uint8_t *) &ip->daddr)[i]);
102 }
103 printf ("\n");
104 printf ("\ticmphdr:\n");
105 printf ("\t\ttype: %s\n",
106 (icmp->type == ICMP_ECHO) ? "ICMP_ECHO" : "ICMP_ECHOREPLY");
107
108 return 0;
109}
110
111static ssize_t
112resolve_arp (void *arp)
113{
114 struct arphdr *resp = (struct arphdr *) arp;
115
116 resp->ar_hrd = __bswap_16 (ARPHRD_ETHER);
117
118 resp->ar_pro = __bswap_16 (0x0800);
119
120 resp->ar_hln = 6;
121 resp->ar_pln = 4;
122
123 resp->ar_op = __bswap_16 (ARPOP_REPLY);
124
125 return sizeof (struct arphdr);
126}
127
128static ssize_t
129resolve_eth_arp (struct ether_arp *eth_arp, void *eth_arp_resp,
130 uint8_t ip_addr[4])
131{
132 struct ether_arp *resp = (struct ether_arp *) eth_arp_resp;
133
134 resolve_arp (&resp->ea_hdr);
135
136 memcpy (resp->arp_tha, eth_arp->arp_sha, 6);
137 memcpy (resp->arp_tpa, eth_arp->arp_spa, 4);
138
139 memcpy (
140 resp->arp_sha,
141 (((struct ether_header *) (eth_arp_resp - sizeof (struct ether_header)))
142 ->ether_shost),
143 6);
144
145 memcpy (resp->arp_spa, ip_addr, 4);
146
147 return sizeof (struct ether_arp);
148}
149
150static ssize_t
151resolve_eth (struct ether_header *eth, void *eth_resp, uint8_t hw_addr[6])
152{
153 struct ether_header *resp = (struct ether_header *) eth_resp;
154 memcpy (resp->ether_dhost, eth->ether_shost, 6);
155
156 memcpy (resp->ether_shost, hw_addr, 6);
157
158 resp->ether_type = eth->ether_type;
159
160 return sizeof (struct ether_header);
161}
162
163static ssize_t
164resolve_ip (struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4])
165{
166 struct iphdr *resp = (struct iphdr *) ip_resp;
167 resp->ihl = 5;
168 resp->version = 4;
169 resp->tos = 0;
170 /*len updated later */
171 resp->tot_len = 0x0000;
172 resp->id = 0;
173 resp->frag_off = 0;
174 resp->ttl = 0x40;
175 resp->protocol = 1;
176 ((uint8_t *) &resp->saddr)[0] = ip_addr[0];
177 ((uint8_t *) &resp->saddr)[1] = ip_addr[1];
178 ((uint8_t *) &resp->saddr)[2] = ip_addr[2];
179 ((uint8_t *) &resp->saddr)[3] = ip_addr[3];
180 resp->daddr = ip->saddr;
181
182 /* resp->check = cksum (resp, sizeof (struct iphdr)); */
183
184 return sizeof (struct iphdr);
185}
186
187static ssize_t
188resolve_icmp (struct icmphdr *icmp, void *icmp_resp)
189{
190 struct icmphdr *resp = (struct icmphdr *) icmp_resp;
191 resp->type = 0x00;
192 resp->code = 0;
193 resp->un.echo.id = icmp->un.echo.id;
194 resp->un.echo.sequence = icmp->un.echo.sequence;
195
196 /*resp->checksum = cksum (resp, sizeof (struct icmphdr)); */
197
198 return sizeof (struct icmphdr);
199}
200
Jakub Grajciare74c04f2021-01-04 11:28:33 +0100201static ssize_t
202generate_eth (struct ether_header *eh, uint8_t hw_daddr[6])
203{
204 uint8_t hw_addr[6];
205 int i;
206 for (i = 0; i < 6; i++)
207 {
208 hw_addr[i] = 'a';
209 }
210 memcpy (eh->ether_shost, hw_addr, 6);
211 memcpy (eh->ether_dhost, hw_daddr, 6);
212
213 eh->ether_type = 0x0008;
214
215 return sizeof (struct ether_header);
216}
217
218static ssize_t
219generate_ip (struct iphdr *ip, uint8_t saddr[4], uint8_t daddr[4])
220{
221 ip->ihl = 5;
222 ip->version = 4;
223 ip->tos = 0;
224 /*len updated later */
225 ip->tot_len = 0x5400;
226 ip->id = 0;
227 ip->frag_off = 0;
228 ip->ttl = 0x40;
229 ip->protocol = 1;
230 /* saddr */
231 ((uint8_t *) &ip->saddr)[0] = saddr[0];
232 ((uint8_t *) &ip->saddr)[1] = saddr[1];
233 ((uint8_t *) &ip->saddr)[2] = saddr[2];
234 ((uint8_t *) &ip->saddr)[3] = saddr[3];
235 /* daddr */
236 ((uint8_t *) &ip->daddr)[0] = daddr[0];
237 ((uint8_t *) &ip->daddr)[1] = daddr[1];
238 ((uint8_t *) &ip->daddr)[2] = daddr[2];
239 ((uint8_t *) &ip->daddr)[3] = daddr[3];
240
241 ip->check = cksum (ip, sizeof (struct iphdr));
242
243 return sizeof (struct iphdr);
244}
245
246static ssize_t
247generate_icmp (struct icmphdr *icmp, uint32_t seq)
248{
249 icmp->type = ICMP_ECHO;
250 icmp->code = 0;
251 icmp->un.echo.id = 0;
252 icmp->un.echo.sequence = seq;
253
254 return sizeof (struct icmphdr);
255}
256
257int
258generate_packet (void *pck, uint32_t *size, uint8_t saddr[4], uint8_t daddr[4],
259 uint8_t hw_daddr[6], uint32_t seq)
260{
261 struct ether_header *eh;
262 struct iphdr *ip;
263 struct icmphdr *icmp;
264
265 *size = 0;
266
267 eh = (struct ether_header *) pck;
268 *size += generate_eth (eh, hw_daddr);
269
270 ip = (struct iphdr *) (pck + *size);
271 *size += generate_ip (ip, saddr, daddr);
272
273 icmp = (struct icmphdr *) (pck + *size);
274 *size += generate_icmp (icmp, seq);
275
276 ((struct icmphdr *) (pck + *size - sizeof (struct icmphdr)))->checksum =
277 cksum (pck + *size - sizeof (struct icmphdr), sizeof (struct icmphdr));
278
279 ip->tot_len = __bswap_16 (*size - sizeof (struct ether_header));
280 ip->check = 0;
281 ip->check = cksum (ip, sizeof (struct iphdr));
282
283 return 0;
284}
285
286int
287generate_packet2 (void *pck, uint32_t *size, uint8_t saddr[4],
288 uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq,
289 icmpr_flow_mode_t mode)
290{
291 struct ether_header *eh;
292 struct iphdr *ip;
293 struct icmphdr *icmp;
294
295 *size = 0;
296
297 if (mode == ICMPR_FLOW_MODE_ETH)
298 {
299 eh = (struct ether_header *) pck;
300 *size += generate_eth (eh, hw_daddr);
301 }
302
303 ip = (struct iphdr *) (pck + *size);
304 *size += generate_ip (ip, saddr, daddr);
305
306 icmp = (struct icmphdr *) (pck + *size);
307 *size += generate_icmp (icmp, seq);
308
309 ((struct icmphdr *) (pck + *size - sizeof (struct icmphdr)))->checksum =
310 cksum (pck + *size - sizeof (struct icmphdr), sizeof (struct icmphdr));
311
312 ip->tot_len = __bswap_16 (*size - sizeof (struct ether_header));
313 ip->check = 0;
314 ip->check = cksum (ip, sizeof (struct iphdr));
315
316 return 0;
317}
318
319#define GET_HEADER(out, hdr, src, off) \
320 do \
321 { \
322 out = (hdr *) (src + off); \
323 off += sizeof (hdr); \
324 } \
325 while (0)
326
327int
Mohsin Kazmi8636a322022-07-18 11:21:05 +0000328resolve_packet (void *pck, uint32_t *size, uint8_t ip_addr[4],
329 uint8_t hw_addr[6])
Jakub Grajciare74c04f2021-01-04 11:28:33 +0100330{
331 struct ether_header *eh;
332 struct ether_arp *eah;
333 struct iphdr *ip;
334 struct icmphdr *icmp;
335 uint32_t offset = 0;
336
337 if (pck == NULL)
338 return 0;
339
Mohsin Kazmi8636a322022-07-18 11:21:05 +0000340#ifdef ICMP_DBG
341 print_packet (pck);
342#endif
343
Jakub Grajciare74c04f2021-01-04 11:28:33 +0100344 GET_HEADER (eh, struct ether_header, pck, offset);
345
346 memcpy (eh->ether_dhost, eh->ether_shost, 6);
347 memcpy (eh->ether_shost, hw_addr, 6);
348
349 if (eh->ether_type == 0x0608)
350 {
351 GET_HEADER (eah, struct ether_arp, pck, offset);
352 struct arphdr *arp = &eah->ea_hdr;
353
354 arp->ar_hrd = __bswap_16 (ARPHRD_ETHER);
355 arp->ar_pro = __bswap_16 (0x0800);
356
357 arp->ar_hln = 6;
358 arp->ar_pln = 4;
359
360 arp->ar_op = __bswap_16 (ARPOP_REPLY);
361
362 memcpy (eah->arp_tha, eah->arp_sha, 6);
363 memcpy (eah->arp_tpa, eah->arp_spa, 4);
364
365 memcpy (eah->arp_sha, eh->ether_shost, 6);
366 memcpy (eah->arp_spa, ip_addr, 4);
367 }
368
369 else if (eh->ether_type == 0x0008)
370 {
371 GET_HEADER (ip, struct iphdr, pck, offset);
372
373 if (ip->protocol == 1)
374 {
375 ip->ihl = 5;
376 ip->version = 4;
377 ip->tos = 0;
378 ip->tot_len = 0x0000;
379 ip->id = 0;
380 ip->frag_off = 0;
381 ip->ttl = 0x40;
382 ip->protocol = 1;
383 ip->check = 0x0000;
384 ip->daddr = ip->saddr;
385 ((uint8_t *) &ip->saddr)[0] = ip_addr[0];
386 ((uint8_t *) &ip->saddr)[1] = ip_addr[1];
387 ((uint8_t *) &ip->saddr)[2] = ip_addr[2];
388 ((uint8_t *) &ip->saddr)[3] = ip_addr[3];
389
390 GET_HEADER (icmp, struct icmphdr, pck, offset);
391
392 icmp->type = 0x00;
393 icmp->code = 0;
394 icmp->checksum = cksum (icmp, sizeof (struct icmphdr));
395
396 /* rest is payload */
397 offset = *size;
398
399 ip->tot_len = __bswap_16 (offset - sizeof (struct ether_header));
400 ip->check = cksum (ip, sizeof (struct iphdr));
401 }
402 }
403
404 assert (offset == *size && "unsupported protocol");
405 return 0;
406}
407
408int
Mohsin Kazmi8636a322022-07-18 11:21:05 +0000409resolve_packet_with_encap (void **pck_, uint32_t *size, uint8_t ip_addr[4])
Jakub Grajciare74c04f2021-01-04 11:28:33 +0100410{
411 struct ether_header *eh;
412 struct iphdr *ip;
413 struct icmphdr *icmp;
414 int32_t offset = 0;
415 uint16_t encap_size = sizeof (struct ether_header);
416 void *pck = *pck_;
417
418 if (pck == NULL)
419 return 0;
420
421 *pck_ -= encap_size;
422 offset -= encap_size;
423
424 GET_HEADER (eh, struct ether_header, pck, offset);
425
426 uint8_t hw_daddr[6];
427 memset (hw_daddr, 0, sizeof (uint8_t) * 6);
428
429 generate_eth (eh, hw_daddr);
430
431 if (eh->ether_type == 0x0008)
432 {
433 GET_HEADER (ip, struct iphdr, pck, offset);
434
435 if (ip->protocol == 1)
436 {
437 ip->ihl = 5;
438 ip->version = 4;
439 ip->tos = 0;
440 ip->tot_len = 0x0000;
441 ip->id = 0;
442 ip->frag_off = 0;
443 ip->ttl = 0x40;
444 ip->protocol = 1;
445 ip->check = 0x0000;
446 ip->daddr = ip->saddr;
447 ((uint8_t *) &ip->saddr)[0] = ip_addr[0];
448 ((uint8_t *) &ip->saddr)[1] = ip_addr[1];
449 ((uint8_t *) &ip->saddr)[2] = ip_addr[2];
450 ((uint8_t *) &ip->saddr)[3] = ip_addr[3];
451
452 GET_HEADER (icmp, struct icmphdr, pck, offset);
453
454 icmp->type = 0x00;
455 icmp->code = 0;
456 icmp->checksum = cksum (icmp, sizeof (struct icmphdr));
457
458 /* rest is payload */
459 offset = *size;
460
461 ip->tot_len = __bswap_16 (offset - sizeof (struct ether_header));
462 ip->check = cksum (ip, sizeof (struct iphdr));
463 }
464 }
465
466 offset += encap_size;
467
468 assert (offset != *size &&
469 "new packet length must be increased by encap size");
470
471 /* overwrite packet size */
472 *size = offset;
473
474 return 0;
475}