summaryrefslogtreecommitdiff
path: root/icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'icmp.c')
-rw-r--r--icmp.c184
1 files changed, 109 insertions, 75 deletions
diff --git a/icmp.c b/icmp.c
index bef1fd6..7951b91 100644
--- a/icmp.c
+++ b/icmp.c
@@ -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;
+}