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 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* 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 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 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 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 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 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