blob: a923f209126403bd49cbc2c90690b5d2a5fff611 [file] [log] [blame]
Jakub Grajciar7c5c40d2017-08-30 10:13:25 +02001/*
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
41#include <icmp_proto.h>
42
43static uint16_t
44cksum (void *addr, ssize_t len)
45{
46 char *data = (char *) addr;
47
48 uint32_t acc = 0xffff;
49
50 ssize_t i;
51 for (i = 0; (i + 1) < len; i += 2)
52 {
53 uint16_t word;
54 memcpy (&word, data + i, 2);
55 acc += ntohs (word);
56 if (acc > 0xffff)
57 acc -= 0xffff;
58 }
59
60 if (len & 1)
61 {
62 uint16_t word = 0;
63 memcpy (&word, data + len - 1, 1);
64 acc += ntohs (word);
65 if (acc > 0xffff)
66 acc -= 0xffff;
67 }
68 return htons (~acc);
69}
70
71int
72print_packet (void *pck)
73{
74 if (pck == NULL)
75 {
76 printf ("ICMP_PROTO: no data\n");
77 return -1;
78 }
79 struct iphdr *ip;
80 struct icmphdr *icmp;
81 ip = (struct iphdr *) pck;
82 icmp = (struct icmphdr *) (pck + sizeof (struct iphdr));
83 printf ("received packet:\n");
84 printf ("\tiphdr:\n");
85 printf ("\t\tihl: %u\n\t\tversion: %u\n\t\tlen: %u\n\t\tid: %u\n",
86 ip->ihl, ip->version, __bswap_16 (ip->tot_len), ip->id);
87 printf ("\t\tprotocol: %u\n", ip->protocol);
88
89 printf ("\t\tsaddr: ");
90 int i;
91 for (i = 0; i < 4; i++)
92 {
93 printf ("%u.", ((uint8_t *) & ip->saddr)[i]);
94 }
95 printf ("\n");
96
97 printf ("\t\tdaddr: ");
98 for (i = 0; i < 4; i++)
99 {
100 printf ("%u.", ((uint8_t *) & ip->daddr)[i]);
101 }
102 printf ("\n");
103 printf ("\ticmphdr:\n");
104 printf ("\t\ttype: %s\n",
105 (icmp->type == ICMP_ECHO) ? "ICMP_ECHO" : "ICMP_ECHOREPLY");
106
107 return 0;
108}
109
110static ssize_t
111resolve_arp (void *arp)
112{
113 struct arphdr *resp = (struct arphdr *) arp;
114
115 resp->ar_hrd = __bswap_16 (ARPHRD_ETHER);
116
117 resp->ar_pro = __bswap_16 (0x0800);
118
119 resp->ar_hln = 6;
120 resp->ar_pln = 4;
121
122 resp->ar_op = __bswap_16 (ARPOP_REPLY);
123
124 return sizeof (struct arphdr);
125}
126
127static ssize_t
128resolve_eth_arp (struct ether_arp *eth_arp, void *eth_arp_resp,
129 uint8_t ip_addr[4])
130{
131 struct ether_arp *resp = (struct ether_arp *) eth_arp_resp;
132
133 resolve_arp (&resp->ea_hdr);
134
135 memcpy (resp->arp_tha, eth_arp->arp_sha, 6);
136 memcpy (resp->arp_tpa, eth_arp->arp_spa, 4);
137
138 memcpy (resp->arp_sha,
139 (((struct ether_header *) (eth_arp_resp -
140 sizeof (struct ether_header)))->
141 ether_shost), 6);
142
143 memcpy (resp->arp_spa, ip_addr, 4);
144
145 return sizeof (struct ether_arp);
146}
147
148static ssize_t
149resolve_eth (struct ether_header *eth, void *eth_resp)
150{
151 struct ether_header *resp = (struct ether_header *) eth_resp;
152 memcpy (resp->ether_dhost, eth->ether_shost, 6);
153
154 uint8_t hw_addr[6];
155 int i;
156 for (i = 0; i < 6; i++)
157 {
158 hw_addr[i] = 'a';
159 }
160 memcpy (resp->ether_shost, hw_addr, 6);
161
162 resp->ether_type = eth->ether_type;
163
164 return sizeof (struct ether_header);
165}
166
167static ssize_t
168resolve_ip (struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4])
169{
170 struct iphdr *resp = (struct iphdr *) ip_resp;
171 resp->ihl = 5;
172 resp->version = 4;
173 resp->tos = 0;
174 /*len updated later */
175 resp->tot_len = 0x5400;
176 resp->id = 0;
177 resp->frag_off = 0;
178 resp->ttl = 0x40;
179 resp->protocol = 1;
180 ((uint8_t *) & resp->saddr)[0] = ip_addr[0];
181 ((uint8_t *) & resp->saddr)[1] = ip_addr[1];
182 ((uint8_t *) & resp->saddr)[2] = ip_addr[2];
183 ((uint8_t *) & resp->saddr)[3] = ip_addr[3];
184 resp->daddr = ip->saddr;
185
186 resp->check = cksum (resp, sizeof (struct iphdr));
187
188 return sizeof (struct iphdr);
189}
190
191static ssize_t
192resolve_icmp (struct icmphdr *icmp, void *icmp_resp)
193{
194 struct icmphdr *resp = (struct icmphdr *) icmp_resp;
195 resp->type = ICMP_ECHOREPLY;
196 resp->code = 0;
197 resp->un.echo.id = icmp->un.echo.id;
198 resp->un.echo.sequence = icmp->un.echo.sequence;
199
200 /*resp->checksum = cksum (resp, sizeof (struct icmphdr)); */
201
202 return sizeof (struct icmphdr);
203}
204
205int
206resolve_packet (void *in_pck, ssize_t in_size,
207 void *out_pck, uint32_t * out_size, uint8_t ip_addr[4])
208{
209 struct ether_header *eh;
210 struct ether_arp *eah;
211 struct iphdr *ip;
212 struct icmphdr *icmp;
213 *out_size = 0;
214
215 eh = (struct ether_header *) in_pck;
216 *out_size = resolve_eth (eh, out_pck);
217
218 if (eh->ether_type == 0x0608)
219 {
220 eah = (struct ether_arp *) (in_pck + *out_size);
221 *out_size += resolve_eth_arp (eah, out_pck + *out_size, ip_addr);
222
223 }
224 else if (eh->ether_type == 0x0008)
225 {
226#ifdef ICMP_DBG
227 print_packet (in_pck + *out_size);
228#endif
229 ip = (struct iphdr *) (in_pck + *out_size);
230 *out_size += resolve_ip (ip, out_pck + *out_size, ip_addr);
231 if (ip->protocol == 1)
232 {
233 icmp = (struct icmphdr *) (in_pck + *out_size);
234 *out_size += resolve_icmp (icmp, out_pck + *out_size);
235 ((struct icmphdr *) (out_pck + *out_size -
236 sizeof (struct icmphdr)))->checksum =
237 cksum (out_pck + *out_size - sizeof (struct icmphdr),
238 sizeof (struct icmphdr));
239 /* payload */
240 memcpy (out_pck + *out_size, in_pck + *out_size,
241 in_size - *out_size);
242 *out_size = in_size;
243 }
244 }
245 return 0;
246}