diff options
Diffstat (limited to 'icmp.c')
-rw-r--r-- | icmp.c | 184 |
1 files changed, 109 insertions, 75 deletions
@@ -21,6 +21,7 @@ static void make_sockaddr_u32(struct sockaddr_in *dst, uint32_t addr) { dst->sin_addr.s_addr = addr; } +__attribute__((unused)) static void make_sockaddr(struct sockaddr_in *dst, const char *ip_address) { make_sockaddr_u32(dst, inet_addr(ip_address)); } @@ -43,6 +44,8 @@ static uint16_t compute_checksum(const void *buf_, size_t buflen) { return res; } +// TODO: Maybe SOCK_{DGRAM,RAW} | SOCK_NONBLOCK to make non-blocking sockets; +// this allows non-blocking reads in the icmpd thread. int icmp_client_open_socket(void) { return socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP); } @@ -51,72 +54,23 @@ int icmp_server_open_socket(void) { return socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); } -struct icmp_client_incoming icmp_client_communicate( - int sock, const char *ip_address, - int id, int seqnum, - const void *data_, size_t length) { - - static uint8_t buffer[ICMP_MAX_PAYLOAD_LENGTH]; - - const uint8_t *data = (const uint8_t*)data_; - - assert(length <= ICMP_MAX_PAYLOAD_LENGTH); - - struct icmp_client_incoming errret = - (struct icmp_client_incoming){.data = NULL, .length = 0, .id = 0, .seqnum = 0}; +struct icmp_incoming icmp_client_communicate( + int sock, uint32_t addr, + int seqnum, + const void *data, size_t length) { - struct sockaddr_in addr; - make_sockaddr(&addr, ip_address); - - struct icmp_echo msg; - memset(&msg, 0, sizeof msg); - msg.type = ICMP_ECHO; - msg.code = 0; - msg.id = htons(id); - msg.seqnum = htons(seqnum); - - memcpy(msg.payload, data, length); - - if (sendto(sock, &msg, ICMP_PAYLOAD_OFFSET + length, 0, (struct sockaddr*)&addr, sizeof addr) < 0) { - return errret; + if (icmp_client_send(sock, addr, seqnum, data, length) < 0) { + return (struct icmp_incoming){.data = NULL, .length = 0, .id = 0, .seqnum = 0, .source_addr = 0}; } - struct msghdr replyhdr; - memset(&replyhdr, 0, sizeof replyhdr); - - struct iovec iov1; - memset(&iov1, 0, sizeof iov1); - iov1.iov_base = &msg; - iov1.iov_len = sizeof msg; - - replyhdr.msg_name = &addr; - replyhdr.msg_namelen = sizeof addr; - replyhdr.msg_iov = &iov1; - replyhdr.msg_iovlen = 1; - - ssize_t nr = recvmsg(sock, &replyhdr, 0); - if (nr < 0) { - return errret; - } - - size_t payloadlen = nr - ICMP_PAYLOAD_OFFSET; - assert(payloadlen <= MAX_DATAGRAM_SIZE); - - memcpy(buffer, msg.payload, payloadlen); - - return (struct icmp_client_incoming){ - .data = buffer, - .length = payloadlen, - .id = ntohs(msg.id), - .seqnum = ntohs(msg.seqnum) - }; + return icmp_client_receive(sock); } -struct icmp_server_incoming icmp_server_receive(int sock) { +struct icmp_incoming icmp_server_receive(int sock) { static uint8_t buffer[ICMP_MAX_PAYLOAD_LENGTH]; - struct icmp_server_incoming errret = - (struct icmp_server_incoming){.data = NULL, .length = 0, .id = 0, .seqnum = 0, .source_addr = 0}; + struct icmp_incoming errret = + (struct icmp_incoming){.data = NULL, .length = 0, .id = 0, .seqnum = 0, .source_addr = 0}; char buf[MAX_IP_PACKET_SIZE]; @@ -140,9 +94,6 @@ struct icmp_server_incoming icmp_server_receive(int sock) { // buf now contains received data starting at the IP header - // printf("Full packet received:\n"); - // xxd(buf, nr); - struct iphdr *hdr = (struct iphdr*)buf; int hdr_len = hdr->ihl * 4; uint32_t saddr = hdr->saddr; @@ -150,20 +101,13 @@ struct icmp_server_incoming icmp_server_receive(int sock) { struct icmp_echo *msg = (struct icmp_echo*)(buf + hdr_len); int msg_len = nr - hdr_len; int payloadlen = msg_len - offsetof(struct icmp_echo, payload); - // printf("Received: type %u code %u id %hu seqnum %hu payload:\n", - // (unsigned)msg->type, (unsigned)msg->code, msg->id, msg->seqnum); - // xxd(msg->payload, payloadlen); - - if (msg->type != ICMP_ECHO && msg->type != ICMP_ECHOREPLY) { - // printf("Not an ICMP_ECHO or ICMP_ECHOREPLY, ignoring\n"); - continue; - } else { + + if (msg->type == ICMP_ECHO) { memcpy(buffer, msg->payload, payloadlen); - return (struct icmp_server_incoming){ + return (struct icmp_incoming){ .data = buffer, .length = payloadlen, - .type = msg->type, .id = ntohs(msg->id), .seqnum = ntohs(msg->seqnum), .source_addr = saddr @@ -172,19 +116,64 @@ struct icmp_server_incoming icmp_server_receive(int sock) { } } -int icmp_server_send_reply( +struct icmp_incoming icmp_client_receive(int sock) { + static uint8_t buffer[ICMP_MAX_PAYLOAD_LENGTH]; + + struct icmp_incoming errret = + (struct icmp_incoming){.data = NULL, .length = 0, .id = 0, .seqnum = 0, .source_addr = 0}; + + struct msghdr replyhdr; + memset(&replyhdr, 0, sizeof replyhdr); + + struct icmp_echo msg; + + struct iovec iov1; + memset(&iov1, 0, sizeof iov1); + iov1.iov_base = &msg; + iov1.iov_len = sizeof msg; + + struct sockaddr_in addr; + + replyhdr.msg_name = &addr; + replyhdr.msg_namelen = sizeof addr; + replyhdr.msg_iov = &iov1; + replyhdr.msg_iovlen = 1; + + ssize_t nr = recvmsg(sock, &replyhdr, 0); + if (nr < 0) { + return errret; + } + + size_t payloadlen = nr - ICMP_PAYLOAD_OFFSET; + assert(payloadlen <= MAX_DATAGRAM_SIZE); + + memcpy(buffer, msg.payload, payloadlen); + + return (struct icmp_incoming){ + .data = buffer, + .length = payloadlen, + .id = ntohs(msg.id), + .seqnum = ntohs(msg.seqnum), + .source_addr = addr.sin_addr.s_addr + }; +} + +static int icmp_server_send( int sock, uint32_t addr_u32, int id, int seqnum, - const void *data_, size_t length) { + const void *data_, size_t length, + int type) { const uint8_t *data = (const uint8_t*)data_; + assert(length <= ICMP_MAX_PAYLOAD_LENGTH); + struct sockaddr_in addr; make_sockaddr_u32(&addr, addr_u32); struct icmp_echo msg; memset(&msg, 0, sizeof msg); - msg.type = ICMP_ECHOREPLY; + msg.type = type; msg.code = 0; msg.id = htons(id); msg.seqnum = htons(seqnum); @@ -201,3 +190,48 @@ int icmp_server_send_reply( return 0; } + +int icmp_server_send_reply( + int sock, uint32_t addr_u32, + int id, int seqnum, + const void *data, size_t length) { + + return icmp_server_send(sock, addr_u32, id, seqnum, data, length, ICMP_ECHOREPLY); +} + +int icmp_server_send_echo( + int sock, uint32_t addr_u32, + int id, int seqnum, + const void *data, size_t length) { + + return icmp_server_send(sock, addr_u32, id, seqnum, data, length, ICMP_ECHO); +} + +int icmp_client_send( + int sock, uint32_t addr_u32, + int seqnum, + const void *data_, size_t length) { + + const uint8_t *data = (const uint8_t*)data_; + + assert(length <= ICMP_MAX_PAYLOAD_LENGTH); + + struct sockaddr_in addr; + make_sockaddr_u32(&addr, addr_u32); + + struct icmp_echo msg; + memset(&msg, 0, sizeof msg); + msg.type = ICMP_ECHO; + msg.code = 0; + msg.id = 0; // overwritten by kernel + msg.seqnum = htons(seqnum); + + if (data == NULL) assert(length == 0); + else memcpy(msg.payload, data, length); + + if (sendto(sock, &msg, ICMP_PAYLOAD_OFFSET + length, 0, (struct sockaddr*)&addr, sizeof addr) < 0) { + return -1; + } + + return 0; +} |