xref: /mOS-networking-stack/core/src/icmp.c (revision cafe7743)
176404edcSAsim Jamshed #include <stdint.h>
276404edcSAsim Jamshed #include <sys/types.h>
376404edcSAsim Jamshed #include <netinet/ip.h>
476404edcSAsim Jamshed #include <string.h>
576404edcSAsim Jamshed 
676404edcSAsim Jamshed #include "mtcp.h"
776404edcSAsim Jamshed #include "icmp.h"
876404edcSAsim Jamshed #include "eth_out.h"
976404edcSAsim Jamshed #include "ip_in.h"
1076404edcSAsim Jamshed #include "ip_out.h"
1176404edcSAsim Jamshed #include "debug.h"
1276404edcSAsim Jamshed #include "arp.h"
1376404edcSAsim Jamshed #include "timer.h"
1476404edcSAsim Jamshed #include "config.h"
1576404edcSAsim Jamshed 
1676404edcSAsim Jamshed #define IP_NEXT_PTR(iph) ((uint8_t *)iph + (iph->ihl << 2))
17*cafe7743SAsim Jamshed void
18*cafe7743SAsim Jamshed DumpICMPPacket(struct icmphdr *icmph, uint32_t saddr, uint32_t daddr);
1976404edcSAsim Jamshed 
2076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
2176404edcSAsim Jamshed 
2276404edcSAsim Jamshed /*
2376404edcSAsim Jamshed struct icmphdr
2476404edcSAsim Jamshed {
2576404edcSAsim Jamshed     uint8_t icmp_type;
2676404edcSAsim Jamshed     uint8_t icmp_code;
2776404edcSAsim Jamshed     uint16_t icmp_checksum;
2876404edcSAsim Jamshed     uint16_t icmp_id;
2976404edcSAsim Jamshed     uint16_t icmp_sequence;
3076404edcSAsim Jamshed };
3176404edcSAsim Jamshed */
3276404edcSAsim Jamshed 
3376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
3476404edcSAsim Jamshed static uint16_t
ICMPChecksum(uint16_t * icmph,int len)3576404edcSAsim Jamshed ICMPChecksum(uint16_t *icmph, int len)
3676404edcSAsim Jamshed {
3776404edcSAsim Jamshed     assert(len >= 0);
3876404edcSAsim Jamshed 
3976404edcSAsim Jamshed     uint16_t ret = 0;
4076404edcSAsim Jamshed     uint32_t sum = 0;
4176404edcSAsim Jamshed     uint16_t odd_byte;
4276404edcSAsim Jamshed 
4376404edcSAsim Jamshed     while (len > 1) {
4476404edcSAsim Jamshed         sum += *icmph++;
4576404edcSAsim Jamshed         len -= 2;
4676404edcSAsim Jamshed     }
4776404edcSAsim Jamshed 
4876404edcSAsim Jamshed     if (len == 1) {
4976404edcSAsim Jamshed         *(uint8_t*)(&odd_byte) = * (uint8_t*)icmph;
5076404edcSAsim Jamshed         sum += odd_byte;
5176404edcSAsim Jamshed     }
5276404edcSAsim Jamshed 
5376404edcSAsim Jamshed     sum =  (sum >> 16) + (sum & 0xffff);
5476404edcSAsim Jamshed     sum += (sum >> 16);
5576404edcSAsim Jamshed     ret =  ~sum;
5676404edcSAsim Jamshed 
5776404edcSAsim Jamshed     return ret;
5876404edcSAsim Jamshed }
5976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
6076404edcSAsim Jamshed 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)6176404edcSAsim Jamshed ICMPOutput(struct mtcp_manager *mtcp, struct pkt_ctx *pctx, uint32_t saddr, uint32_t daddr,
6276404edcSAsim Jamshed         uint8_t icmp_type, uint8_t icmp_code, uint16_t icmp_id, uint16_t icmp_seq,
6376404edcSAsim Jamshed         uint8_t *icmpd, uint16_t len)
6476404edcSAsim Jamshed {
6576404edcSAsim Jamshed     struct iphdr *iph;
6676404edcSAsim Jamshed     int32_t nif;
6776404edcSAsim Jamshed     uint8_t *haddr;
6876404edcSAsim Jamshed     struct icmphdr *icmph;
6976404edcSAsim Jamshed     uint32_t pktlen = sizeof(struct iphdr) + sizeof(struct icmphdr) + len;
7076404edcSAsim Jamshed     struct timeval cur_ts = {0};
7176404edcSAsim Jamshed     uint32_t ts;
7276404edcSAsim Jamshed 
7376404edcSAsim Jamshed     /* Get hardware interface to forward the packet*/
7476404edcSAsim Jamshed     nif = GetOutputInterface(daddr);
7576404edcSAsim Jamshed     if (nif < 0)
7676404edcSAsim Jamshed         return (uint8_t *) ERROR;
7776404edcSAsim Jamshed 
7876404edcSAsim Jamshed     /* Get next hop MAC address */
7976404edcSAsim Jamshed     haddr = GetDestinationHWaddr(daddr);
8076404edcSAsim Jamshed     if (!haddr) {
8176404edcSAsim Jamshed         uint8_t *da = (uint8_t *)&daddr;
8276404edcSAsim Jamshed         TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
8376404edcSAsim Jamshed                    "is not in ARP table!\n",
8476404edcSAsim Jamshed                    da[0], da[1], da[2], da[3]);
8576404edcSAsim Jamshed 	/* ARP requests will not be created if it's a standalone middlebox */
8676404edcSAsim Jamshed 	if (!pctx->forward)
8776404edcSAsim Jamshed 		RequestARP(mtcp, daddr, nif, mtcp->cur_ts);
8876404edcSAsim Jamshed         haddr = GetDestinationHWaddr(daddr);
8976404edcSAsim Jamshed     }
9076404edcSAsim Jamshed 
9176404edcSAsim Jamshed     /* Check if we have valid next hop address */
9276404edcSAsim Jamshed     if (!haddr)
9376404edcSAsim Jamshed 	    return (uint8_t *) ERROR;
9476404edcSAsim Jamshed 
9576404edcSAsim Jamshed     /* Set up timestamp for EthernetOutput */
9676404edcSAsim Jamshed     gettimeofday(&cur_ts, NULL);
9776404edcSAsim Jamshed     ts = TIMEVAL_TO_TS(&cur_ts);
9876404edcSAsim Jamshed 
9976404edcSAsim Jamshed     /* Allocate a buffer */
10076404edcSAsim Jamshed     iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP, nif, haddr, pktlen, ts);
10176404edcSAsim Jamshed     if (!iph)
10276404edcSAsim Jamshed 	    return (uint8_t *) ERROR;
10376404edcSAsim Jamshed 
10476404edcSAsim Jamshed     /* Fill in the ip header */
10576404edcSAsim Jamshed     iph->ihl = IP_HEADER_LEN >> 2;
10676404edcSAsim Jamshed     iph->version = 4;
10776404edcSAsim Jamshed     iph->tos = 0;
10876404edcSAsim Jamshed     iph->tot_len = htons(pktlen);
10976404edcSAsim Jamshed     iph->id = htons(0);
11076404edcSAsim Jamshed     iph->frag_off = htons(IP_DF);
11176404edcSAsim Jamshed     iph->ttl = 64;
11276404edcSAsim Jamshed     iph->protocol = IPPROTO_ICMP;
11376404edcSAsim Jamshed     iph->saddr = saddr;
11476404edcSAsim Jamshed     iph->daddr = daddr;
11576404edcSAsim Jamshed     iph->check = 0;
11676404edcSAsim Jamshed     iph->check = ip_fast_csum(iph, iph->ihl);
11776404edcSAsim Jamshed 
11876404edcSAsim Jamshed     icmph = (struct icmphdr *) IP_NEXT_PTR(iph);
11976404edcSAsim Jamshed 
12076404edcSAsim Jamshed     /* Fill in the icmp header */
12176404edcSAsim Jamshed     icmph->icmp_type = icmp_type;
12276404edcSAsim Jamshed     icmph->icmp_code = icmp_code;
12376404edcSAsim Jamshed     icmph->icmp_checksum = 0;
12476404edcSAsim Jamshed     ICMP_ECHO_SET_ID(icmph, htons(icmp_id));
12576404edcSAsim Jamshed     ICMP_ECHO_SET_SEQ(icmph, htons(icmp_seq));
12676404edcSAsim Jamshed 
12776404edcSAsim Jamshed     /* Fill in the icmp data */
12876404edcSAsim Jamshed     if(len > 0)
12976404edcSAsim Jamshed         memcpy((void *) (icmph + 1), icmpd, len);
13076404edcSAsim Jamshed 
13176404edcSAsim Jamshed     /* Calculate ICMP Checksum with header and data */
13276404edcSAsim Jamshed     icmph->icmp_checksum =
13376404edcSAsim Jamshed                        ICMPChecksum((uint16_t *)icmph, sizeof(struct icmphdr) + len);
13476404edcSAsim Jamshed 
13576404edcSAsim Jamshed #if DBGMSG
13676404edcSAsim Jamshed     DumpICMPPacket(icmph, saddr, daddr);
13776404edcSAsim Jamshed #endif
13876404edcSAsim Jamshed     return (uint8_t *)(iph + 1);
13976404edcSAsim Jamshed }
14076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
14176404edcSAsim Jamshed 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)14276404edcSAsim Jamshed RequestICMP(mtcp_manager_t mtcp, struct pkt_ctx *pctx, uint32_t saddr, uint32_t daddr,
14376404edcSAsim Jamshed         uint16_t icmp_id, uint16_t icmp_sequence,
14476404edcSAsim Jamshed         uint8_t *icmpd, uint16_t len)
14576404edcSAsim Jamshed {
14676404edcSAsim Jamshed     /* send icmp request with given parameters */
14776404edcSAsim Jamshed     ICMPOutput(mtcp, pctx, saddr, daddr, ICMP_ECHO, 0, ntohs(icmp_id), ntohs(icmp_sequence),
14876404edcSAsim Jamshed                icmpd, len);
14976404edcSAsim Jamshed }
15076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
15176404edcSAsim Jamshed static int
ProcessICMPECHORequest(mtcp_manager_t mtcp,struct pkt_ctx * pctx,struct icmphdr * icmph)15276404edcSAsim Jamshed ProcessICMPECHORequest(mtcp_manager_t mtcp, struct pkt_ctx *pctx, struct icmphdr *icmph)
15376404edcSAsim Jamshed {
15476404edcSAsim Jamshed     int ret = 0;
15576404edcSAsim Jamshed 
15676404edcSAsim Jamshed     /* Check correctness of ICMP checksum and send ICMP echo reply */
15776404edcSAsim Jamshed     if (ICMPChecksum((uint16_t *) icmph, pctx->p.ip_len - (pctx->p.iph->ihl << 2) ))
15876404edcSAsim Jamshed         ret = ERROR;
15976404edcSAsim Jamshed     else
16076404edcSAsim Jamshed         ICMPOutput(mtcp, pctx, pctx->p.iph->daddr, pctx->p.iph->saddr, ICMP_ECHOREPLY, 0,
16176404edcSAsim Jamshed                    ntohs(ICMP_ECHO_GET_ID(icmph)), ntohs(ICMP_ECHO_GET_SEQ(icmph)), (uint8_t *) (icmph + 1),
16276404edcSAsim Jamshed                    (uint16_t) (pctx->p.ip_len - (pctx->p.iph->ihl << 2) - sizeof(struct icmphdr)) );
16376404edcSAsim Jamshed 
16476404edcSAsim Jamshed     return ret;
16576404edcSAsim Jamshed }
16676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
16776404edcSAsim Jamshed static int
ProcessICMPECHOReply(mtcp_manager_t mtcp,struct pkt_ctx * pctx,struct icmphdr * icmph)16876404edcSAsim Jamshed ProcessICMPECHOReply(mtcp_manager_t mtcp, struct pkt_ctx *pctx, struct icmphdr *icmph)
16976404edcSAsim Jamshed {
17076404edcSAsim Jamshed 
17176404edcSAsim Jamshed     /* XXX We can allow sending ping request from mOS app. IMHO, it's bad */
17276404edcSAsim Jamshed 
17376404edcSAsim Jamshed #if 0
17476404edcSAsim Jamshed     uint8_t type, code;
17576404edcSAsim Jamshed     uint16_t seq, id;
17676404edcSAsim Jamshed 
17776404edcSAsim Jamshed     /* Extract ICMP field from packet */
17876404edcSAsim Jamshed     type = icmph->icmp_type;
17976404edcSAsim Jamshed     code = icmph->icmp_code;
18076404edcSAsim Jamshed     seq  = ntohs(ICMP_ECHO_GET_SEQ(icmph));
18176404edcSAsim Jamshed     id   = ntohs(ICMP_ECHO_GET_ID(icmph));
18276404edcSAsim Jamshed #endif
18376404edcSAsim Jamshed     return 0;
18476404edcSAsim Jamshed }
18576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
18676404edcSAsim Jamshed int
ProcessICMPPacket(mtcp_manager_t mtcp,struct pkt_ctx * pctx)18776404edcSAsim Jamshed ProcessICMPPacket(mtcp_manager_t mtcp, struct pkt_ctx *pctx)
18876404edcSAsim Jamshed {
18976404edcSAsim Jamshed     struct icmphdr *icmph = (struct icmphdr *) IP_NEXT_PTR(pctx->p.iph);
19076404edcSAsim Jamshed     int i;
19176404edcSAsim Jamshed     int to_me = FALSE;
19276404edcSAsim Jamshed 
19376404edcSAsim Jamshed     /* process the icmp messages destined to me */
19476404edcSAsim Jamshed     for (i = 0; i < g_config.mos->netdev_table->num; i++) {
19576404edcSAsim Jamshed         if (pctx->p.iph->daddr == g_config.mos->netdev_table->ent[i]->ip_addr) {
19676404edcSAsim Jamshed             to_me = TRUE;
19776404edcSAsim Jamshed         }
19876404edcSAsim Jamshed     }
19976404edcSAsim Jamshed 
20076404edcSAsim Jamshed     if (!to_me)
20176404edcSAsim Jamshed         return FALSE;
20276404edcSAsim Jamshed 
20376404edcSAsim Jamshed     switch (icmph->icmp_type)
20476404edcSAsim Jamshed     {
20576404edcSAsim Jamshed         case ICMP_ECHO:
20676404edcSAsim Jamshed             ProcessICMPECHORequest(mtcp, pctx, icmph);
20776404edcSAsim Jamshed             break;
20876404edcSAsim Jamshed 
20976404edcSAsim Jamshed         case ICMP_ECHOREPLY:
21076404edcSAsim Jamshed             ProcessICMPECHOReply(mtcp, pctx, icmph);
21176404edcSAsim Jamshed             break;
21276404edcSAsim Jamshed 
21376404edcSAsim Jamshed         case ICMP_DEST_UNREACH:
21476404edcSAsim Jamshed             TRACE_INFO("[INFO] ICMP Destination Unreachable message received\n");
21576404edcSAsim Jamshed             break;
21676404edcSAsim Jamshed 
21776404edcSAsim Jamshed         case ICMP_TIME_EXCEEDED:
21876404edcSAsim Jamshed             TRACE_INFO("[INFO] ICMP Time Exceeded message received\n");
21976404edcSAsim Jamshed             break;
22076404edcSAsim Jamshed 
22176404edcSAsim Jamshed         default:
22276404edcSAsim Jamshed             TRACE_INFO("[INFO] Unsupported ICMP message type %x received\n",
22376404edcSAsim Jamshed                        icmph->icmp_type);
22476404edcSAsim Jamshed             break;
22576404edcSAsim Jamshed     }
22676404edcSAsim Jamshed 
22776404edcSAsim Jamshed     return TRUE;
22876404edcSAsim Jamshed }
22976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
23076404edcSAsim Jamshed void
DumpICMPPacket(struct icmphdr * icmph,uint32_t saddr,uint32_t daddr)23176404edcSAsim Jamshed DumpICMPPacket(struct icmphdr *icmph, uint32_t saddr, uint32_t daddr)
23276404edcSAsim Jamshed {
23376404edcSAsim Jamshed     uint8_t *t;
23476404edcSAsim Jamshed 
23576404edcSAsim Jamshed     fprintf(stderr, "ICMP header: \n");
23676404edcSAsim Jamshed     fprintf(stderr, "Type: %d, "
23776404edcSAsim Jamshed             "Code: %d, ID: %d, Sequence: %d\n",
23876404edcSAsim Jamshed             icmph->icmp_type, icmph->icmp_code,
23976404edcSAsim Jamshed             ICMP_ECHO_GET_ID(icmph), ICMP_ECHO_GET_SEQ(icmph));
24076404edcSAsim Jamshed 
24176404edcSAsim Jamshed     t = (uint8_t *)&saddr;
24276404edcSAsim Jamshed     fprintf(stderr, "Sender IP: %u.%u.%u.%u\n",
24376404edcSAsim Jamshed             t[0], t[1], t[2], t[3]);
24476404edcSAsim Jamshed 
24576404edcSAsim Jamshed     t = (uint8_t *)&daddr;
24676404edcSAsim Jamshed     fprintf(stderr, "Target IP: %u.%u.%u.%u\n",
24776404edcSAsim Jamshed             t[0], t[1], t[2], t[3]);
24876404edcSAsim Jamshed }
24976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
25076404edcSAsim Jamshed #undef IP_NEXT_PTR
251