summaryrefslogtreecommitdiffstats
path: root/daemon/icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/icmp.c')
-rw-r--r--daemon/icmp.c87
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;
+}