-
Notifications
You must be signed in to change notification settings - Fork 39
/
icmp_handler.c
128 lines (106 loc) · 4.39 KB
/
icmp_handler.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <signal.h>
#ifdef __linux__
#include <linux/errqueue.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#endif
#include <errno.h>
#include <stdio.h>
#include "log.h"
#include "utp.h"
#include "dht.h"
#include "network.h"
#ifdef __linux__
typedef struct iovec iovec;
typedef struct msghdr msghdr;
typedef struct cmsghdr cmsghdr;
typedef struct sock_extended_err sock_extended_err;
void icmp_handler(network *n)
{
for (;;) {
uint8_t vec_buf[4096];
uint8_t ancillary_buf[4096];
iovec iov = { vec_buf, sizeof(vec_buf) };
sockaddr_storage remote;
msghdr msg = {
.msg_name = (sockaddr *)&remote,
.msg_namelen = sizeof(remote),
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_flags = 0,
.msg_control = ancillary_buf,
.msg_controllen = sizeof(ancillary_buf)
};
ssize_t len = recvmsg(n->fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
}
debug("recvmsg MSG_ERRQUEUE failed %d %s\n", errno, strerror(errno));
break;
}
if (remote.ss_family != AF_INET && remote.ss_family != AF_INET6) {
debug("%s address family not supported:%d\n", __func__, remote.ss_family);
break;
}
socklen_t remote_len = sockaddr_get_length((const sockaddr *)&remote);
for (cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_IP && cmsg->cmsg_level != SOL_IPV6) {
debug("Unhandled errqueue level: %d\n", cmsg->cmsg_level);
continue;
}
if (cmsg->cmsg_type == IP_RECVERR) {
ddebug("errqueue: IP_RECVERR, SOL_IP, len %zd\n", cmsg->cmsg_len);
} else if (cmsg->cmsg_type == IPV6_RECVERR) {
ddebug("errqueue: IPV6_RECVERR, SOL_IP, len %zd\n", cmsg->cmsg_len);
} else {
debug("Unhandled errqueue type: %d\n", cmsg->cmsg_type);
continue;
}
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
getnameinfo((const sockaddr *)&remote, remote_len, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV);
ddebug("Remote host: %s:%s\n", host, serv);
sock_extended_err *e = (sock_extended_err *)CMSG_DATA(cmsg);
if (!e) {
debug("errqueue: sock_extended_err is NULL?\n");
continue;
}
if (e->ee_origin != SO_EE_ORIGIN_ICMP && e->ee_origin != SO_EE_ORIGIN_ICMP6) {
debug("errqueue: Unexpected origin: %d\n", e->ee_origin);
continue;
}
ddebug(" errno:%d origin:%d type:%d code:%d info:%d data:%d\n",
e->ee_errno, e->ee_origin, e->ee_type, e->ee_code, e->ee_info, e->ee_data);
// "Node that caused the error"
// "Node that generated the error"
ddebug("msg_flags: %d", msg.msg_flags);
if (o_debug >= 2) {
if (msg.msg_flags & MSG_TRUNC)
fprintf(stderr, " MSG_TRUNC");
if (msg.msg_flags & MSG_CTRUNC)
fprintf(stderr, " MSG_CTRUNC");
if (msg.msg_flags & MSG_EOR)
fprintf(stderr, " MSG_EOR");
if (msg.msg_flags & MSG_OOB)
fprintf(stderr, " MSG_OOB");
if (msg.msg_flags & MSG_ERRQUEUE)
fprintf(stderr, " MSG_ERRQUEUE");
fprintf(stderr, "\n");
}
if (o_debug >= 3) {
hexdump(vec_buf, len);
}
if (e->ee_type == 3 && e->ee_code == 4) {
ddebug("ICMP type 3, code 4: Fragmentation error, discovered MTU %d\n", e->ee_info);
utp_process_icmp_fragmentation(n->utp, vec_buf, len, (const sockaddr *)&remote, remote_len, e->ee_info);
// XXX: can dht do anything with fragmentation?
} else {
ddebug("ICMP type %d, code %d\n", e->ee_type, e->ee_code);
utp_process_icmp_error(n->utp, vec_buf, len, (const sockaddr *)&remote, remote_len);
dht_process_icmp_error(n->dht, vec_buf, len, (const sockaddr *)&remote, remote_len);
}
}
}
}
#endif