-
Notifications
You must be signed in to change notification settings - Fork 2
/
ip.c
107 lines (93 loc) · 2.02 KB
/
ip.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "list.h"
struct iphdr {
uint8_t version : 4;
uint8_t ihl : 4;
uint8_t tos;
uint16_t len;
uint16_t id;
uint16_t flags : 3;
uint16_t frag_offset : 13;
uint8_t ttl;
uint8_t proto;
uint16_t csum;
uint32_t saddr;
uint32_t daddr;
} __attribute__((packed));
struct icmp_v4 {
uint8_t type;
uint8_t code;
uint16_t csum;
uint8_t data[];
} __attribute__((packed));
struct icmp_v4_echo {
uint16_t id;
uint16_t seq;
uint8_t data[];
} __attribute__((packed));
#define ICMP 0x01
uint16_t checksum(void *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
* Taken from https://tools.ietf.org/html/rfc1071
*/
register uint32_t sum = 0;
uint16_t * ptr = addr;
while( count > 1 ) {
/* This is the inner loop */
sum += * ptr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (uint8_t *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
int ip_in(struct iphdr *hdr)
{
assert(hdr);
if (checksum(hdr, sizeof(*hdr))) {
printf("ip: incorrect checksum\n");
return -EINVAL;
}
if (hdr->daddr != 0x0200000a)
return -EINVAL;
if (hdr->proto == ICMP) {
struct icmp_v4 *icmp = (struct icmp_v4 *) ((uintptr_t) hdr + sizeof(*hdr));
if (icmp->type == 0x8) {
uint32_t tmp;
tmp = hdr->daddr;
hdr->daddr = hdr->saddr;
hdr->saddr = tmp;
/* Recalculate checksum */
hdr->csum = 0x0;
hdr->csum = checksum(hdr, sizeof(*hdr));
icmp->type = 0x0;
icmp->csum = 0x0;
icmp->csum = checksum(icmp, ntohs(hdr->len) - sizeof(*hdr));
}
}
return 0;
}