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