From d6d784cc333cdc1ff496c1fc562ffd2335a39e92 Mon Sep 17 00:00:00 2001 From: Jason Fesler Date: Tue, 17 Feb 2015 12:11:17 -0800 Subject: Rename to mtu1280d --- Makefile | 7 + README.md | 6 +- init.d/mtu1280 | 6 +- mtu1280.c | 525 -------------------------------------------------------- mtu1280d.c | 525 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ upstart/mtu1280 | 2 +- 6 files changed, 539 insertions(+), 532 deletions(-) create mode 100644 Makefile delete mode 100644 mtu1280.c create mode 100644 mtu1280d.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..132420e --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ + +mtu1280: mtu1280d.c + gcc -o mtu1280 mtu1280d.c -lnetfilter_queue + +install: mtu1280d + /usr/bin/install -c mtu1280d /usr/sbin/mtu1280d + \ No newline at end of file diff --git a/README.md b/README.md index e5915b0..214e03d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -mtu1280 - emulates serving via a low MTU IPv6 tunnel +mtu1280d - emulates serving via a low MTU IPv6 tunnel ---------------------------------------------------- This program is will generate ICMPv6 "Packet Too Big" -responses with an MTU of 1280. mtu1280 will connect to +responses with an MTU of 1280. mtu1280d will connect to a netfilter_queue socket, listening for packets; and respond to all packets sent to that queue. @@ -50,7 +50,7 @@ iptables-restore /etc/iptables/rules.v4 ip6tables-restore /etc/iptables/rules.v6 ``` -/etc/iptables/rules.v6 (simplified version, only includes mtu1280 rule) +/etc/iptables/rules.v6 (simplified version, only includes mtu1280d rule) ``` # Generated by ip6tables-save v1.4.21 on Tue Feb 17 10:54:23 2015 *filter diff --git a/init.d/mtu1280 b/init.d/mtu1280 index 8d4d3e6..72103c9 100644 --- a/init.d/mtu1280 +++ b/init.d/mtu1280 @@ -1,11 +1,11 @@ #! /bin/sh ### BEGIN INIT INFO -# Provides: mtu1280 +# Provides: mtu1280d # Required-Start: $network $syslog # Required-Stop: $network $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 -# Short-Description: mtu1280 Synthetic ICMPv6 Packet Too Big response +# Short-Description: mtu1280d Synthetic ICMPv6 Packet Too Big response # Description: This file should be used to construct scripts to be # placed in /etc/init.d. ### END INIT INFO @@ -17,7 +17,7 @@ # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="Synthetic ICMPv6 Packet Too Big response" -NAME=mtu1280 +NAME=mtu1280d DAEMON=/usr/sbin/$NAME DAEMON_ARGS="-d -q 1280" PIDFILE=/var/run/$NAME.pid diff --git a/mtu1280.c b/mtu1280.c deleted file mode 100644 index 7948af9..0000000 --- a/mtu1280.c +++ /dev/null @@ -1,525 +0,0 @@ -// Thanks to Austin Marton -// https://austinmarton.wordpress.com/2011/09/14/sending-raw-ethernet-packets-from-a-specific-interface-in-c-on-linux/ -// csum() is borrowed from Austin; and csum_3() is derived from csum(). - -// Portions of this file derived from libnetfilter_queue-1.0.2/utils/nfqnl_test.c -// (C) 2005 by Harald Welte -// Particularly the bits that interface with netfilter (and the trigger for this being GPLv2 instead of MIT license) - -// Code not otherwise borrowed is -// (C) 2015 by Jason Fesler -// Principally: anything to do with ICMPv6 responses -// The uglier it looks, the more likely it is mine. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// netfilter - lots of stuff pilfered from nfqnl_test.c -#include /* for NF_ACCEPT */ -#include - -#define MTU 1280 -#define ETHER_SIZE (6+6+2) -#define IPV6HDR_SIZE 40 -#define ICMP6_SIZE 8 -#define PAYLOAD_SIZE (MTU-(IPV6HDR_SIZE+ICMP6_SIZE)) -#define ETHER_CRC_SIZE 4 -#define ETHER_TOTAL_SIZE (MTU + ETHER_SIZE) - -typedef struct fullframe -{ - u_int8_t ether_frame[ETHER_SIZE]; - u_int8_t ipv6_header[IPV6HDR_SIZE]; - u_int8_t icmp6_header[ICMP6_SIZE]; - u_int8_t payload[PAYLOAD_SIZE]; -} fullframe; - -int -sockfd (void) -{ - static sock = 0; - if (!sock) - { - sock = socket (AF_PACKET, SOCK_RAW, IPPROTO_RAW); - } - if (sock == -1) - { - perror ("socket"); - } -} - -uint8_t * -macaddr_for_interface (int i) -{ - static int last_i = 0xfffff; - static uint8_t buffer[6]; - static uint8_t devname[IF_NAMESIZE]; - - if (i != last_i) - { - int s = sockfd (); // * Need a random socket FD to do ioctl against - char *interface = NULL; - memset (buffer, 0, sizeof (buffer)); - interface = if_indextoname (i, devname); - struct ifreq ifr; - - if (interface) - { - printf ("Looked up %d, found %s ", i, interface); - - // Use ioctl() to look up interface name and get its MAC address. - memset (&ifr, 0, sizeof (ifr)); - snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface); - if (ioctl (s, SIOCGIFHWADDR, &ifr) < 0) - { - perror ("ioctl() failed to get source MAC address "); - exit (1); - } - memcpy (buffer, ifr.ifr_hwaddr.sa_data, 6); - - } - - } - printf ("interface %d mac %02x:%02x:%02x:%02x:%02x:%02x", - i, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], - buffer[5]); - - return buffer; -} - - -void -hexdump (char *s, uint8_t * p, int n) -{ - int i; - printf ("\nHEXDUMP: %s\n", s); - for (i = 0; i < n; i++) - { - if (i % 16 == 0) - { - printf ("%04x: ", i); - } - printf ("%02x", p[i]); - if (i % 2 == 1) - { - printf (" "); - } - if (i % 4 == 3) - { - printf (" "); - } - if (i % 16 == 15) - { - printf ("\n"); - } - } - printf ("\n"); -} - - -uint16_t -csum (uint16_t * buf, int count) -{ - uint32_t sum; - for (sum = 0; count > 0; count -= 2) - sum += *buf++; - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return (uint16_t) (~sum); -} - -uint16_t -csum_3 (uint16_t * buf1, int count1, uint16_t * buf2, int count2, - uint16_t * buf3, int count3) -{ - uint32_t sum; - for (sum = 0; count1 > 0; count1 -= 2) - sum += *buf1++; - for (; count2 > 0; count2 -= 2) - sum += *buf2++; - for (; count3 > 0; count3 -= 2) - sum += *buf3++; - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return (uint16_t) (~sum); -} - - - - -/* returns packet id */ -static u_int32_t -block_pkt (struct nfq_data *tb) -{ - int id = 0; - struct nfqnl_msg_packet_hdr *ph; - struct nfqnl_msg_packet_hw *hwph; - u_int32_t mark, ifi; - int ret; - int data_len; - int copy_len; - unsigned char *data; - uint16_t c; - - // Where to address the raw packets - fill this in - // as we go - struct sockaddr_ll socket_address; - memset (&socket_address, 0, sizeof (socket_address)); - - - // I'm tired of fighting all the crud, - // so I'm goingto just use a big block. - fullframe buffer; - memset (&buffer, 0, sizeof (buffer)); - assert (sizeof (buffer) == ETHER_TOTAL_SIZE); - - // We need - // Ethernet header - // IPv6 header - // IPCMPv6 header - // As much of the original payload as possible - // Final ether CRC - - - // Get the packet ID. NEeded for netfilter_queue response. - fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); - ph = nfq_get_msg_packet_hdr (tb); - if (ph) - { - id = ntohl (ph->packet_id); - printf ("hw_protocol=0x%04x hook=%u id=%u ", - ntohs (ph->hw_protocol), ph->hook, id); - } - - // Get the data payload from netfilter_queue - fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); - ret = nfq_get_payload (tb, &data); - if (ret >= 0) - printf ("payload_len=%d ", ret); - data_len = ret; - copy_len = (data_len > PAYLOAD_SIZE) ? PAYLOAD_SIZE : data_len; - printf ("copy_len=%d ", copy_len); - - - - // What MAC address sent us this packet? - // We intend to send the outbound packet - // back to the same place. - hwph = nfq_get_packet_hw (tb); - if (hwph) - { - int i, hlen = ntohs (hwph->hw_addrlen); - - printf ("hw_src_addr="); - for (i = 0; i < hlen - 1; i++) - printf ("%02x:", hwph->hw_addr[i]); - printf ("%02x ", hwph->hw_addr[hlen - 1]); - - // Ethernet frame destination - memcpy (&buffer.ether_frame[0], hwph->hw_addr, 6); - memcpy (socket_address.sll_addr, hwph->hw_addr, 6); - socket_address.sll_halen = ETH_ALEN; - } - - // TODO: Ethernet frame source - - // Ethernet frame type - buffer.ether_frame[12] = ETH_P_IPV6 / 256; - buffer.ether_frame[13] = ETH_P_IPV6 % 256; - - // Show the ethernet frame - hexdump ("DUMP: ether_frame", buffer.ether_frame, - sizeof (buffer.ether_frame)); - - - // Start creating the IPv6 header - buffer.ipv6_header[0] = 0x60; // IPv6 "version=6" - - // What is the payload length? - int plength = copy_len + ICMP6_SIZE; - buffer.ipv6_header[4] = plength / 256; - buffer.ipv6_header[5] = plength % 256; - - // What is the next header? - buffer.ipv6_header[6] = 0x3a; // ICMPv6 - buffer.ipv6_header[7] = 0xff; // Hop limit - - // Source address, Destination Address - // Just swap from what we saw in our input packet - memcpy (&buffer.ipv6_header[8], &data[24], 16); - memcpy (&buffer.ipv6_header[24], &data[8], 16); - - hexdump ("IP6 HEADER:", buffer.ipv6_header, sizeof (buffer.ipv6_header)); - - // ICMPv6 header - buffer.icmp6_header[0] = 2; // Type 2 Packet Too Big - buffer.icmp6_header[1] = 0; // Code (not used) - - // TODO Checksum - buffer.icmp6_header[2] = 0; // TODO Checksum - buffer.icmp6_header[3] = 0; // TODO checksum - - // MTU expressed as 32 bits - buffer.icmp6_header[4] = (MTU >> 24) & 0xff; - buffer.icmp6_header[5] = (MTU >> 16) & 0xff; - buffer.icmp6_header[6] = (MTU >> 8) & 0xff; - buffer.icmp6_header[7] = MTU & 0xff; - - memcpy (buffer.payload, data, copy_len); - hexdump ("ICMP6", buffer.icmp6_header, - sizeof (buffer.icmp6_header) + copy_len); - - u_int8_t pseudoheader[40]; - memcpy (pseudoheader, &buffer.ipv6_header[8], 32); - pseudoheader[32] = 0; // length never more than 0xffff - pseudoheader[33] = 0; // length never more than 0xffff - pseudoheader[34] = (ICMP6_SIZE + copy_len) / 256; - pseudoheader[35] = (ICMP6_SIZE + copy_len) % 256; - pseudoheader[36] = 0; // zero - pseudoheader[37] = 0; // zero - pseudoheader[38] = 0; // zero - pseudoheader[39] = 58; // ICMPv6 header code - - c = csum_3 ((uint16_t *) pseudoheader, sizeof (pseudoheader), - (uint16_t *) buffer.icmp6_header, sizeof (buffer.icmp6_header), - (uint16_t *) buffer.payload, copy_len); - buffer.icmp6_header[2] = c % 256; - buffer.icmp6_header[3] = c / 256; - - hexdump ("PseudoHeader", pseudoheader, sizeof (pseudoheader)); - - - hexdump ("ICMP6", buffer.icmp6_header, - sizeof (buffer.icmp6_header) + copy_len); - - - - - - - // Device ID that the packet came from - fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); - ifi = nfq_get_indev (tb); - if (ifi) - { - printf ("indev=%u ", ifi); - socket_address.sll_ifindex = ifi; - memcpy (&buffer.ether_frame[6], macaddr_for_interface (ifi), 6); - } - - fputc ('\n', stdout); - fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); - - int tx_len = ETHER_SIZE + IPV6HDR_SIZE + ICMP6_SIZE + copy_len; - if (sendto - (sockfd (), &buffer, tx_len, 0, (struct sockaddr *) &socket_address, - sizeof (struct sockaddr_ll)) < 0) - printf ("Send failed\n"); - - - - - return id; -} - - - -/* returns packet id */ -static u_int32_t -print_pkt (struct nfq_data *tb) -{ - int id = 0; - struct nfqnl_msg_packet_hdr *ph; - struct nfqnl_msg_packet_hw *hwph; - u_int32_t mark, ifi; - int ret; - unsigned char *data; - - ph = nfq_get_msg_packet_hdr (tb); - if (ph) - { - id = ntohl (ph->packet_id); - printf ("hw_protocol=0x%04x hook=%u id=%u ", - ntohs (ph->hw_protocol), ph->hook, id); - } - - hwph = nfq_get_packet_hw (tb); - if (hwph) - { - int i, hlen = ntohs (hwph->hw_addrlen); - - printf ("hw_src_addr="); - for (i = 0; i < hlen - 1; i++) - printf ("%02x:", hwph->hw_addr[i]); - printf ("%02x ", hwph->hw_addr[hlen - 1]); - } - - mark = nfq_get_nfmark (tb); - if (mark) - printf ("mark=%u ", mark); - - ifi = nfq_get_indev (tb); - if (ifi) - printf ("indev=%u ", ifi); - - ifi = nfq_get_outdev (tb); - if (ifi) - printf ("outdev=%u ", ifi); - ifi = nfq_get_physindev (tb); - if (ifi) - printf ("physindev=%u ", ifi); - - ifi = nfq_get_physoutdev (tb); - if (ifi) - printf ("physoutdev=%u ", ifi); - - ret = nfq_get_payload (tb, &data); - if (ret >= 0) - printf ("payload_len=%d ", ret); - - fputc ('\n', stdout); - - return id; -} - - -static int -cb (struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, - struct nfq_data *nfa, void *data) -{ - static u_int32_t id; -// id = print_pkt(nfa); - printf ("entering callback\n"); - id = block_pkt (nfa); - return nfq_set_verdict (qh, id, NF_DROP, 0, NULL); -} - - -int -main (int argc, char **argv) -{ - struct nfq_handle *h; - struct nfq_q_handle *qh; - struct nfnl_handle *nh; - int fd; - int rv; - unsigned int queue = 1280; // -q - unsigned int do_fork = 0; // -d - char *interface; - char buf[4096] __attribute__ ((aligned)); - -// Getopt - int c; - int opterr = 0; - while ((c = getopt (argc, argv, "dq:")) != -1) - switch (c) - { - case 'd': - fprintf (stderr, "setting\n"); - do_fork = 1; - fprintf (stderr, "set!\n"); - break; - case 'q': - queue = strtol (optarg, NULL, 10); - break; - case '?': - if (optopt == 'q') - fprintf (stderr, "Option -%c requires an argument.\n", optopt); - else if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); - return 1; - default: - abort (); - } - - - - - printf ("opening library handle\n"); - h = nfq_open (); - if (!h) - { - fprintf (stdout, "error during nfq_open()\n"); - exit (1); - } - - printf ("unbinding existing nf_queue handler for AF_INET6 (if any)\n"); - if (nfq_unbind_pf (h, AF_INET6) < 0) - { - fprintf (stdout, "error during nfq_unbind_pf()\n"); - if (getuid () != 0) - { - fprintf (stderr, "%s: must be ran as root\n", argv[0]); - } - exit (1); - } - - printf ("binding nfnetlink_queue as nf_queue handler for AF_INET6\n"); - if (nfq_bind_pf (h, AF_INET6) < 0) - { - fprintf (stdout, "error during nfq_bind_pf()\n"); - exit (1); - } - - printf ("binding this socket to queue '%u'\n", queue); - qh = nfq_create_queue (h, queue, &cb, NULL); - if (!qh) - { - fprintf (stdout, "error during nfq_create_queue()\n"); - exit (1); - } - - - printf ("setting copy_packet mode\n"); - if (nfq_set_mode (qh, NFQNL_COPY_PACKET, 0xffff) < 0) - { - fprintf (stdout, "can't set packet_copy mode\n"); - exit (1); - } - - - if (do_fork) - { - fprintf (stdout, "forking to background\n"); - daemon (0, 0); - } - - - fd = nfq_fd (h); - - while ((rv = recv (fd, buf, sizeof (buf), 0)) && rv >= 0) - { - printf ("pkt received\n"); - nfq_handle_packet (h, buf, rv); - } - - printf ("unbinding from queue 0\n"); - nfq_destroy_queue (qh); - -#ifdef INSANE - /* normally, applications SHOULD NOT issue this command, since - * it detaches other programs/sockets from AF_INET6, too ! */ - printf ("unbinding from AF_INET6\n"); - nfq_unbind_pf (h, AF_INET6); -#endif - - printf ("closing library handle\n"); - nfq_close (h); - - exit (0); -} diff --git a/mtu1280d.c b/mtu1280d.c new file mode 100644 index 0000000..7948af9 --- /dev/null +++ b/mtu1280d.c @@ -0,0 +1,525 @@ +// Thanks to Austin Marton +// https://austinmarton.wordpress.com/2011/09/14/sending-raw-ethernet-packets-from-a-specific-interface-in-c-on-linux/ +// csum() is borrowed from Austin; and csum_3() is derived from csum(). + +// Portions of this file derived from libnetfilter_queue-1.0.2/utils/nfqnl_test.c +// (C) 2005 by Harald Welte +// Particularly the bits that interface with netfilter (and the trigger for this being GPLv2 instead of MIT license) + +// Code not otherwise borrowed is +// (C) 2015 by Jason Fesler +// Principally: anything to do with ICMPv6 responses +// The uglier it looks, the more likely it is mine. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// netfilter - lots of stuff pilfered from nfqnl_test.c +#include /* for NF_ACCEPT */ +#include + +#define MTU 1280 +#define ETHER_SIZE (6+6+2) +#define IPV6HDR_SIZE 40 +#define ICMP6_SIZE 8 +#define PAYLOAD_SIZE (MTU-(IPV6HDR_SIZE+ICMP6_SIZE)) +#define ETHER_CRC_SIZE 4 +#define ETHER_TOTAL_SIZE (MTU + ETHER_SIZE) + +typedef struct fullframe +{ + u_int8_t ether_frame[ETHER_SIZE]; + u_int8_t ipv6_header[IPV6HDR_SIZE]; + u_int8_t icmp6_header[ICMP6_SIZE]; + u_int8_t payload[PAYLOAD_SIZE]; +} fullframe; + +int +sockfd (void) +{ + static sock = 0; + if (!sock) + { + sock = socket (AF_PACKET, SOCK_RAW, IPPROTO_RAW); + } + if (sock == -1) + { + perror ("socket"); + } +} + +uint8_t * +macaddr_for_interface (int i) +{ + static int last_i = 0xfffff; + static uint8_t buffer[6]; + static uint8_t devname[IF_NAMESIZE]; + + if (i != last_i) + { + int s = sockfd (); // * Need a random socket FD to do ioctl against + char *interface = NULL; + memset (buffer, 0, sizeof (buffer)); + interface = if_indextoname (i, devname); + struct ifreq ifr; + + if (interface) + { + printf ("Looked up %d, found %s ", i, interface); + + // Use ioctl() to look up interface name and get its MAC address. + memset (&ifr, 0, sizeof (ifr)); + snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface); + if (ioctl (s, SIOCGIFHWADDR, &ifr) < 0) + { + perror ("ioctl() failed to get source MAC address "); + exit (1); + } + memcpy (buffer, ifr.ifr_hwaddr.sa_data, 6); + + } + + } + printf ("interface %d mac %02x:%02x:%02x:%02x:%02x:%02x", + i, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], + buffer[5]); + + return buffer; +} + + +void +hexdump (char *s, uint8_t * p, int n) +{ + int i; + printf ("\nHEXDUMP: %s\n", s); + for (i = 0; i < n; i++) + { + if (i % 16 == 0) + { + printf ("%04x: ", i); + } + printf ("%02x", p[i]); + if (i % 2 == 1) + { + printf (" "); + } + if (i % 4 == 3) + { + printf (" "); + } + if (i % 16 == 15) + { + printf ("\n"); + } + } + printf ("\n"); +} + + +uint16_t +csum (uint16_t * buf, int count) +{ + uint32_t sum; + for (sum = 0; count > 0; count -= 2) + sum += *buf++; + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return (uint16_t) (~sum); +} + +uint16_t +csum_3 (uint16_t * buf1, int count1, uint16_t * buf2, int count2, + uint16_t * buf3, int count3) +{ + uint32_t sum; + for (sum = 0; count1 > 0; count1 -= 2) + sum += *buf1++; + for (; count2 > 0; count2 -= 2) + sum += *buf2++; + for (; count3 > 0; count3 -= 2) + sum += *buf3++; + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return (uint16_t) (~sum); +} + + + + +/* returns packet id */ +static u_int32_t +block_pkt (struct nfq_data *tb) +{ + int id = 0; + struct nfqnl_msg_packet_hdr *ph; + struct nfqnl_msg_packet_hw *hwph; + u_int32_t mark, ifi; + int ret; + int data_len; + int copy_len; + unsigned char *data; + uint16_t c; + + // Where to address the raw packets - fill this in + // as we go + struct sockaddr_ll socket_address; + memset (&socket_address, 0, sizeof (socket_address)); + + + // I'm tired of fighting all the crud, + // so I'm goingto just use a big block. + fullframe buffer; + memset (&buffer, 0, sizeof (buffer)); + assert (sizeof (buffer) == ETHER_TOTAL_SIZE); + + // We need + // Ethernet header + // IPv6 header + // IPCMPv6 header + // As much of the original payload as possible + // Final ether CRC + + + // Get the packet ID. NEeded for netfilter_queue response. + fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); + ph = nfq_get_msg_packet_hdr (tb); + if (ph) + { + id = ntohl (ph->packet_id); + printf ("hw_protocol=0x%04x hook=%u id=%u ", + ntohs (ph->hw_protocol), ph->hook, id); + } + + // Get the data payload from netfilter_queue + fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); + ret = nfq_get_payload (tb, &data); + if (ret >= 0) + printf ("payload_len=%d ", ret); + data_len = ret; + copy_len = (data_len > PAYLOAD_SIZE) ? PAYLOAD_SIZE : data_len; + printf ("copy_len=%d ", copy_len); + + + + // What MAC address sent us this packet? + // We intend to send the outbound packet + // back to the same place. + hwph = nfq_get_packet_hw (tb); + if (hwph) + { + int i, hlen = ntohs (hwph->hw_addrlen); + + printf ("hw_src_addr="); + for (i = 0; i < hlen - 1; i++) + printf ("%02x:", hwph->hw_addr[i]); + printf ("%02x ", hwph->hw_addr[hlen - 1]); + + // Ethernet frame destination + memcpy (&buffer.ether_frame[0], hwph->hw_addr, 6); + memcpy (socket_address.sll_addr, hwph->hw_addr, 6); + socket_address.sll_halen = ETH_ALEN; + } + + // TODO: Ethernet frame source + + // Ethernet frame type + buffer.ether_frame[12] = ETH_P_IPV6 / 256; + buffer.ether_frame[13] = ETH_P_IPV6 % 256; + + // Show the ethernet frame + hexdump ("DUMP: ether_frame", buffer.ether_frame, + sizeof (buffer.ether_frame)); + + + // Start creating the IPv6 header + buffer.ipv6_header[0] = 0x60; // IPv6 "version=6" + + // What is the payload length? + int plength = copy_len + ICMP6_SIZE; + buffer.ipv6_header[4] = plength / 256; + buffer.ipv6_header[5] = plength % 256; + + // What is the next header? + buffer.ipv6_header[6] = 0x3a; // ICMPv6 + buffer.ipv6_header[7] = 0xff; // Hop limit + + // Source address, Destination Address + // Just swap from what we saw in our input packet + memcpy (&buffer.ipv6_header[8], &data[24], 16); + memcpy (&buffer.ipv6_header[24], &data[8], 16); + + hexdump ("IP6 HEADER:", buffer.ipv6_header, sizeof (buffer.ipv6_header)); + + // ICMPv6 header + buffer.icmp6_header[0] = 2; // Type 2 Packet Too Big + buffer.icmp6_header[1] = 0; // Code (not used) + + // TODO Checksum + buffer.icmp6_header[2] = 0; // TODO Checksum + buffer.icmp6_header[3] = 0; // TODO checksum + + // MTU expressed as 32 bits + buffer.icmp6_header[4] = (MTU >> 24) & 0xff; + buffer.icmp6_header[5] = (MTU >> 16) & 0xff; + buffer.icmp6_header[6] = (MTU >> 8) & 0xff; + buffer.icmp6_header[7] = MTU & 0xff; + + memcpy (buffer.payload, data, copy_len); + hexdump ("ICMP6", buffer.icmp6_header, + sizeof (buffer.icmp6_header) + copy_len); + + u_int8_t pseudoheader[40]; + memcpy (pseudoheader, &buffer.ipv6_header[8], 32); + pseudoheader[32] = 0; // length never more than 0xffff + pseudoheader[33] = 0; // length never more than 0xffff + pseudoheader[34] = (ICMP6_SIZE + copy_len) / 256; + pseudoheader[35] = (ICMP6_SIZE + copy_len) % 256; + pseudoheader[36] = 0; // zero + pseudoheader[37] = 0; // zero + pseudoheader[38] = 0; // zero + pseudoheader[39] = 58; // ICMPv6 header code + + c = csum_3 ((uint16_t *) pseudoheader, sizeof (pseudoheader), + (uint16_t *) buffer.icmp6_header, sizeof (buffer.icmp6_header), + (uint16_t *) buffer.payload, copy_len); + buffer.icmp6_header[2] = c % 256; + buffer.icmp6_header[3] = c / 256; + + hexdump ("PseudoHeader", pseudoheader, sizeof (pseudoheader)); + + + hexdump ("ICMP6", buffer.icmp6_header, + sizeof (buffer.icmp6_header) + copy_len); + + + + + + + // Device ID that the packet came from + fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); + ifi = nfq_get_indev (tb); + if (ifi) + { + printf ("indev=%u ", ifi); + socket_address.sll_ifindex = ifi; + memcpy (&buffer.ether_frame[6], macaddr_for_interface (ifi), 6); + } + + fputc ('\n', stdout); + fprintf (stdout, "TRACE: %s %i\n", __FILE__, __LINE__); + + int tx_len = ETHER_SIZE + IPV6HDR_SIZE + ICMP6_SIZE + copy_len; + if (sendto + (sockfd (), &buffer, tx_len, 0, (struct sockaddr *) &socket_address, + sizeof (struct sockaddr_ll)) < 0) + printf ("Send failed\n"); + + + + + return id; +} + + + +/* returns packet id */ +static u_int32_t +print_pkt (struct nfq_data *tb) +{ + int id = 0; + struct nfqnl_msg_packet_hdr *ph; + struct nfqnl_msg_packet_hw *hwph; + u_int32_t mark, ifi; + int ret; + unsigned char *data; + + ph = nfq_get_msg_packet_hdr (tb); + if (ph) + { + id = ntohl (ph->packet_id); + printf ("hw_protocol=0x%04x hook=%u id=%u ", + ntohs (ph->hw_protocol), ph->hook, id); + } + + hwph = nfq_get_packet_hw (tb); + if (hwph) + { + int i, hlen = ntohs (hwph->hw_addrlen); + + printf ("hw_src_addr="); + for (i = 0; i < hlen - 1; i++) + printf ("%02x:", hwph->hw_addr[i]); + printf ("%02x ", hwph->hw_addr[hlen - 1]); + } + + mark = nfq_get_nfmark (tb); + if (mark) + printf ("mark=%u ", mark); + + ifi = nfq_get_indev (tb); + if (ifi) + printf ("indev=%u ", ifi); + + ifi = nfq_get_outdev (tb); + if (ifi) + printf ("outdev=%u ", ifi); + ifi = nfq_get_physindev (tb); + if (ifi) + printf ("physindev=%u ", ifi); + + ifi = nfq_get_physoutdev (tb); + if (ifi) + printf ("physoutdev=%u ", ifi); + + ret = nfq_get_payload (tb, &data); + if (ret >= 0) + printf ("payload_len=%d ", ret); + + fputc ('\n', stdout); + + return id; +} + + +static int +cb (struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, + struct nfq_data *nfa, void *data) +{ + static u_int32_t id; +// id = print_pkt(nfa); + printf ("entering callback\n"); + id = block_pkt (nfa); + return nfq_set_verdict (qh, id, NF_DROP, 0, NULL); +} + + +int +main (int argc, char **argv) +{ + struct nfq_handle *h; + struct nfq_q_handle *qh; + struct nfnl_handle *nh; + int fd; + int rv; + unsigned int queue = 1280; // -q + unsigned int do_fork = 0; // -d + char *interface; + char buf[4096] __attribute__ ((aligned)); + +// Getopt + int c; + int opterr = 0; + while ((c = getopt (argc, argv, "dq:")) != -1) + switch (c) + { + case 'd': + fprintf (stderr, "setting\n"); + do_fork = 1; + fprintf (stderr, "set!\n"); + break; + case 'q': + queue = strtol (optarg, NULL, 10); + break; + case '?': + if (optopt == 'q') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); + return 1; + default: + abort (); + } + + + + + printf ("opening library handle\n"); + h = nfq_open (); + if (!h) + { + fprintf (stdout, "error during nfq_open()\n"); + exit (1); + } + + printf ("unbinding existing nf_queue handler for AF_INET6 (if any)\n"); + if (nfq_unbind_pf (h, AF_INET6) < 0) + { + fprintf (stdout, "error during nfq_unbind_pf()\n"); + if (getuid () != 0) + { + fprintf (stderr, "%s: must be ran as root\n", argv[0]); + } + exit (1); + } + + printf ("binding nfnetlink_queue as nf_queue handler for AF_INET6\n"); + if (nfq_bind_pf (h, AF_INET6) < 0) + { + fprintf (stdout, "error during nfq_bind_pf()\n"); + exit (1); + } + + printf ("binding this socket to queue '%u'\n", queue); + qh = nfq_create_queue (h, queue, &cb, NULL); + if (!qh) + { + fprintf (stdout, "error during nfq_create_queue()\n"); + exit (1); + } + + + printf ("setting copy_packet mode\n"); + if (nfq_set_mode (qh, NFQNL_COPY_PACKET, 0xffff) < 0) + { + fprintf (stdout, "can't set packet_copy mode\n"); + exit (1); + } + + + if (do_fork) + { + fprintf (stdout, "forking to background\n"); + daemon (0, 0); + } + + + fd = nfq_fd (h); + + while ((rv = recv (fd, buf, sizeof (buf), 0)) && rv >= 0) + { + printf ("pkt received\n"); + nfq_handle_packet (h, buf, rv); + } + + printf ("unbinding from queue 0\n"); + nfq_destroy_queue (qh); + +#ifdef INSANE + /* normally, applications SHOULD NOT issue this command, since + * it detaches other programs/sockets from AF_INET6, too ! */ + printf ("unbinding from AF_INET6\n"); + nfq_unbind_pf (h, AF_INET6); +#endif + + printf ("closing library handle\n"); + nfq_close (h); + + exit (0); +} diff --git a/upstart/mtu1280 b/upstart/mtu1280 index a96cdf9..ee996aa 100755 --- a/upstart/mtu1280 +++ b/upstart/mtu1280 @@ -15,4 +15,4 @@ umask 022 console none -exec /usr/sbin/mtu1280 -q 1280 +exec /usr/sbin/mtu1280d -q 1280 -- cgit v1.2.3