diff options
Diffstat (limited to 'daemon/icmp.c')
-rw-r--r-- | daemon/icmp.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/daemon/icmp.c b/daemon/icmp.c new file mode 100644 index 0000000..7252b7c --- /dev/null +++ b/daemon/icmp.c @@ -0,0 +1,87 @@ +#include <stdio.h> +#include <string.h> +#include <netinet/in.h> + +#include <linux/ip.h> +#include <linux/icmp.h> +#include <linux/tcp.h> + +#include "icmp.h" + +#define BUFSIZE (10*1024) + +static int icmp_socket = -1; + +guint16 ipsum(guint8 *p, guint l) { + guint32 sum = 0; + guint i; + + for (i = 0; i < l-1; i += 2) + sum += (p[i] << 8) + p[i+1]; + + if (i < l) + sum += p[i] << 8; + + sum = (sum & 0xFFFF) + (sum >> 16); + sum = (sum & 0xFFFF) + (sum >> 16); + + return ~sum; +} + + +int reply_icmp_error(ipq_packet_msg_t *m, int code) { + static guint8 buf[BUFSIZE]; + struct iphdr* ip = (struct iphdr*) m->payload; + struct icmphdr *icmp = (struct icmphdr*) buf; + guint l, tl; + struct sockaddr_in sa; + + icmp->type = 3; + icmp->code = code; + icmp->checksum = 0; + icmp->un.frag.__unused = 0; + icmp->un.frag.mtu = 0; + + l = ip->ihl*4 + 8; + memcpy(&buf[sizeof(struct icmphdr)], m->payload, l); + + tl = l + sizeof(struct icmphdr); + icmp->checksum = htons(ipsum((guint8*) icmp, tl)); + + sa.sin_family = AF_INET; + sa.sin_port = 0; + sa.sin_addr.s_addr = ip->saddr; + + + if (sendto(icmp_socket, icmp, tl, 0, (struct sockaddr*) &sa, sizeof(sa)) < 0) { + perror("sendto()"); + return -1; + } + + return 0; +} + +int icmp_init() { + int enable = 1; + + if ((icmp_socket = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { + perror("socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)"); + return -1; + + } + + if (setsockopt(icmp_socket, SOL_SOCKET, SO_BROADCAST, (char *)&enable, sizeof(enable)) < 0) { + perror("setsockopt(.., SOL_SOCKET, SO_BROADCAST)"); + return -1; + } + + return 0; +} + + +void icmp_done() { + if (icmp_socket >= 0) + close(icmp_socket); + + icmp_socket = -1; +} |