1 #include <stdint.h>
2 #include <sys/types.h>
3 #include <netinet/ip.h>
4 #include <string.h>
5
6 #include "mtcp.h"
7 #include "icmp.h"
8 #include "eth_out.h"
9 #include "ip_in.h"
10 #include "ip_out.h"
11 #include "debug.h"
12 #include "arp.h"
13 #include "timer.h"
14 #include "config.h"
15
16 #define IP_NEXT_PTR(iph) ((uint8_t *)iph + (iph->ihl << 2))
17 void
18 DumpICMPPacket(struct icmphdr *icmph, uint32_t saddr, uint32_t daddr);
19
20 /*----------------------------------------------------------------------------*/
21
22 /*
23 struct icmphdr
24 {
25 uint8_t icmp_type;
26 uint8_t icmp_code;
27 uint16_t icmp_checksum;
28 uint16_t icmp_id;
29 uint16_t icmp_sequence;
30 };
31 */
32
33 /*----------------------------------------------------------------------------*/
34 static uint16_t
ICMPChecksum(uint16_t * icmph,int len)35 ICMPChecksum(uint16_t *icmph, int len)
36 {
37 assert(len >= 0);
38
39 uint16_t ret = 0;
40 uint32_t sum = 0;
41 uint16_t odd_byte;
42
43 while (len > 1) {
44 sum += *icmph++;
45 len -= 2;
46 }
47
48 if (len == 1) {
49 *(uint8_t*)(&odd_byte) = * (uint8_t*)icmph;
50 sum += odd_byte;
51 }
52
53 sum = (sum >> 16) + (sum & 0xffff);
54 sum += (sum >> 16);
55 ret = ~sum;
56
57 return ret;
58 }
59 /*----------------------------------------------------------------------------*/
60 static uint8_t*
ICMPOutput(struct mtcp_manager * mtcp,struct pkt_ctx * pctx,uint32_t saddr,uint32_t daddr,uint8_t icmp_type,uint8_t icmp_code,uint16_t icmp_id,uint16_t icmp_seq,uint8_t * icmpd,uint16_t len)61 ICMPOutput(struct mtcp_manager *mtcp, struct pkt_ctx *pctx, uint32_t saddr, uint32_t daddr,
62 uint8_t icmp_type, uint8_t icmp_code, uint16_t icmp_id, uint16_t icmp_seq,
63 uint8_t *icmpd, uint16_t len)
64 {
65 struct iphdr *iph;
66 int32_t nif;
67 uint8_t *haddr;
68 struct icmphdr *icmph;
69 uint32_t pktlen = sizeof(struct iphdr) + sizeof(struct icmphdr) + len;
70 struct timeval cur_ts = {0};
71 uint32_t ts;
72
73 /* Get hardware interface to forward the packet*/
74 nif = GetOutputInterface(daddr);
75 if (nif < 0)
76 return (uint8_t *) ERROR;
77
78 /* Get next hop MAC address */
79 haddr = GetDestinationHWaddr(daddr);
80 if (!haddr) {
81 uint8_t *da = (uint8_t *)&daddr;
82 TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
83 "is not in ARP table!\n",
84 da[0], da[1], da[2], da[3]);
85 /* ARP requests will not be created if it's a standalone middlebox */
86 if (!pctx->forward)
87 RequestARP(mtcp, daddr, nif, mtcp->cur_ts);
88 haddr = GetDestinationHWaddr(daddr);
89 }
90
91 /* Check if we have valid next hop address */
92 if (!haddr)
93 return (uint8_t *) ERROR;
94
95 /* Set up timestamp for EthernetOutput */
96 gettimeofday(&cur_ts, NULL);
97 ts = TIMEVAL_TO_TS(&cur_ts);
98
99 /* Allocate a buffer */
100 iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP, nif, haddr, pktlen, ts);
101 if (!iph)
102 return (uint8_t *) ERROR;
103
104 /* Fill in the ip header */
105 iph->ihl = IP_HEADER_LEN >> 2;
106 iph->version = 4;
107 iph->tos = 0;
108 iph->tot_len = htons(pktlen);
109 iph->id = htons(0);
110 iph->frag_off = htons(IP_DF);
111 iph->ttl = 64;
112 iph->protocol = IPPROTO_ICMP;
113 iph->saddr = saddr;
114 iph->daddr = daddr;
115 iph->check = 0;
116 iph->check = ip_fast_csum(iph, iph->ihl);
117
118 icmph = (struct icmphdr *) IP_NEXT_PTR(iph);
119
120 /* Fill in the icmp header */
121 icmph->icmp_type = icmp_type;
122 icmph->icmp_code = icmp_code;
123 icmph->icmp_checksum = 0;
124 ICMP_ECHO_SET_ID(icmph, htons(icmp_id));
125 ICMP_ECHO_SET_SEQ(icmph, htons(icmp_seq));
126
127 /* Fill in the icmp data */
128 if(len > 0)
129 memcpy((void *) (icmph + 1), icmpd, len);
130
131 /* Calculate ICMP Checksum with header and data */
132 icmph->icmp_checksum =
133 ICMPChecksum((uint16_t *)icmph, sizeof(struct icmphdr) + len);
134
135 #if DBGMSG
136 DumpICMPPacket(icmph, saddr, daddr);
137 #endif
138 return (uint8_t *)(iph + 1);
139 }
140 /*----------------------------------------------------------------------------*/
141 void
RequestICMP(mtcp_manager_t mtcp,struct pkt_ctx * pctx,uint32_t saddr,uint32_t daddr,uint16_t icmp_id,uint16_t icmp_sequence,uint8_t * icmpd,uint16_t len)142 RequestICMP(mtcp_manager_t mtcp, struct pkt_ctx *pctx, uint32_t saddr, uint32_t daddr,
143 uint16_t icmp_id, uint16_t icmp_sequence,
144 uint8_t *icmpd, uint16_t len)
145 {
146 /* send icmp request with given parameters */
147 ICMPOutput(mtcp, pctx, saddr, daddr, ICMP_ECHO, 0, ntohs(icmp_id), ntohs(icmp_sequence),
148 icmpd, len);
149 }
150 /*----------------------------------------------------------------------------*/
151 static int
ProcessICMPECHORequest(mtcp_manager_t mtcp,struct pkt_ctx * pctx,struct icmphdr * icmph)152 ProcessICMPECHORequest(mtcp_manager_t mtcp, struct pkt_ctx *pctx, struct icmphdr *icmph)
153 {
154 int ret = 0;
155
156 /* Check correctness of ICMP checksum and send ICMP echo reply */
157 if (ICMPChecksum((uint16_t *) icmph, pctx->p.ip_len - (pctx->p.iph->ihl << 2) ))
158 ret = ERROR;
159 else
160 ICMPOutput(mtcp, pctx, pctx->p.iph->daddr, pctx->p.iph->saddr, ICMP_ECHOREPLY, 0,
161 ntohs(ICMP_ECHO_GET_ID(icmph)), ntohs(ICMP_ECHO_GET_SEQ(icmph)), (uint8_t *) (icmph + 1),
162 (uint16_t) (pctx->p.ip_len - (pctx->p.iph->ihl << 2) - sizeof(struct icmphdr)) );
163
164 return ret;
165 }
166 /*----------------------------------------------------------------------------*/
167 static int
ProcessICMPECHOReply(mtcp_manager_t mtcp,struct pkt_ctx * pctx,struct icmphdr * icmph)168 ProcessICMPECHOReply(mtcp_manager_t mtcp, struct pkt_ctx *pctx, struct icmphdr *icmph)
169 {
170
171 /* XXX We can allow sending ping request from mOS app. IMHO, it's bad */
172
173 #if 0
174 uint8_t type, code;
175 uint16_t seq, id;
176
177 /* Extract ICMP field from packet */
178 type = icmph->icmp_type;
179 code = icmph->icmp_code;
180 seq = ntohs(ICMP_ECHO_GET_SEQ(icmph));
181 id = ntohs(ICMP_ECHO_GET_ID(icmph));
182 #endif
183 return 0;
184 }
185 /*----------------------------------------------------------------------------*/
186 int
ProcessICMPPacket(mtcp_manager_t mtcp,struct pkt_ctx * pctx)187 ProcessICMPPacket(mtcp_manager_t mtcp, struct pkt_ctx *pctx)
188 {
189 struct icmphdr *icmph = (struct icmphdr *) IP_NEXT_PTR(pctx->p.iph);
190 int i;
191 int to_me = FALSE;
192
193 /* process the icmp messages destined to me */
194 for (i = 0; i < g_config.mos->netdev_table->num; i++) {
195 if (pctx->p.iph->daddr == g_config.mos->netdev_table->ent[i]->ip_addr) {
196 to_me = TRUE;
197 }
198 }
199
200 if (!to_me)
201 return FALSE;
202
203 switch (icmph->icmp_type)
204 {
205 case ICMP_ECHO:
206 ProcessICMPECHORequest(mtcp, pctx, icmph);
207 break;
208
209 case ICMP_ECHOREPLY:
210 ProcessICMPECHOReply(mtcp, pctx, icmph);
211 break;
212
213 case ICMP_DEST_UNREACH:
214 TRACE_INFO("[INFO] ICMP Destination Unreachable message received\n");
215 break;
216
217 case ICMP_TIME_EXCEEDED:
218 TRACE_INFO("[INFO] ICMP Time Exceeded message received\n");
219 break;
220
221 default:
222 TRACE_INFO("[INFO] Unsupported ICMP message type %x received\n",
223 icmph->icmp_type);
224 break;
225 }
226
227 return TRUE;
228 }
229 /*----------------------------------------------------------------------------*/
230 void
DumpICMPPacket(struct icmphdr * icmph,uint32_t saddr,uint32_t daddr)231 DumpICMPPacket(struct icmphdr *icmph, uint32_t saddr, uint32_t daddr)
232 {
233 uint8_t *t;
234
235 fprintf(stderr, "ICMP header: \n");
236 fprintf(stderr, "Type: %d, "
237 "Code: %d, ID: %d, Sequence: %d\n",
238 icmph->icmp_type, icmph->icmp_code,
239 ICMP_ECHO_GET_ID(icmph), ICMP_ECHO_GET_SEQ(icmph));
240
241 t = (uint8_t *)&saddr;
242 fprintf(stderr, "Sender IP: %u.%u.%u.%u\n",
243 t[0], t[1], t[2], t[3]);
244
245 t = (uint8_t *)&daddr;
246 fprintf(stderr, "Target IP: %u.%u.%u.%u\n",
247 t[0], t[1], t[2], t[3]);
248 }
249 /*----------------------------------------------------------------------------*/
250 #undef IP_NEXT_PTR
251