diff --git a/.gitignore b/.gitignore index 95290bb..f6a5486 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,10 @@ src/Makefile.in Makefile src/Makefile INSTALL +src/autoconfig.h.in.in +src/autoconfig.h.in +src/autoconfig.h +src/stamp-h1 # build *.o diff --git a/README b/README index 56baad8..c2f0667 100644 --- a/README +++ b/README @@ -5,25 +5,17 @@ About ----- WrapSix is a fast NAT64 implementation. You also need a DNS64 server (e.g. BIND). -Before compiling, don't forget to configure Wrapsix in files src/wrapper.c and -src/wrapper.h. +Before compiling, don't forget to configure Wrapsix in files src/wrapper.c. Configuration ------------- -INTERFACE Interface on which WrapSix should operate, e.g. eth0. -PREFIX NAT64 prefix; at least /96, the default is standard - 64:ff9b::/96. Input it without the information about prefix - length, i.e. just 64:ff9b::. -IPV4_ADDR IPv4 address which is dedicated for WrapSix and is not assigned - to the host operating system. HOST_IPV6_ADDR IPv6 address which represents the host, i.e. which is assigned to the operating system. It's used in ICMP error messages. HOST_IPV4_ADDR IPv4 address which represents the host, i.e. which is assigned to the operating system. It's used in ICMP error messages. -MTU Minimum MTU in your IPv6 network; default is 1280, but you can - set it to a greater value (up to 1500). -PACKET_BUFFER Size of a buffer for incoming packets; it's strongly recommended - to leave its value as is (i.e. 1514). + +WrapSix uses configuration file wrapsix.conf from configuration directory set in +"./configure" phase, which is by default /usr/local/etc. Installation ------------ diff --git a/configure.ac b/configure.ac index ebc1da0..064deba 100644 --- a/configure.ac +++ b/configure.ac @@ -14,6 +14,7 @@ AC_CONFIG_FILES([ src/Makefile ]) AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADER([src/autoconfig.h.in]) ### # Configuration options @@ -26,11 +27,14 @@ AC_ARG_ENABLE([debug], if test "x$debug" = "xyes"; then AS_COMPILER_FLAGS(AM_CFLAGS, "-g -ggdb -O0 -pipe -pedantic -Wshadow -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wold-style-definition -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wformat-nonliteral -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs -Wundef -Waggregate-return -Wnested-externs -Wunsafe-loop-optimizations -Winvalid-pch") - AC_DEFINE([DEBUG]) + AC_DEFINE([DEBUG], [], [Turn on debug mode]) else AS_COMPILER_FLAGS(AM_CFLAGS, "-O2") fi + +AC_DEFINE([SYSCONFDIR], "--sysconfdir--", [Configuration files directory]) + ### # Final commands ### diff --git a/src/Makefile.am b/src/Makefile.am index f880ef0..bc7ae48 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,9 @@ sbin_PROGRAMS = wrapsix wrapsix_SOURCES = \ arp.c arp.h \ + autoconfig.h \ checksum.c checksum.h \ + config.c config.h \ ethernet.h \ icmp.c icmp.h \ ipv4.c ipv4.h \ @@ -14,3 +16,6 @@ wrapsix_SOURCES = \ transmitter.c transmitter.h \ udp.c udp.h \ wrapper.c wrapper.h + +autoconfig.h: + sed -e 's|--sysconfdir--|$(sysconfdir)|' autoconfig.h.in > autoconfig.h diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..fb69b2f --- /dev/null +++ b/src/config.c @@ -0,0 +1,183 @@ +/* + * WrapSix + * Copyright (C) 2008-2013 xHire + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "config.h" +#include "log.h" +#include "wrapper.h" + +#define SYNTAX_ERROR(file, line, pos, fatal) { \ + log_error("Syntax error in configuration file %s on " \ + "line %d, position %d", file, line, pos); \ + fclose(f); \ + if (fatal) { \ + exit(1); \ + } else { \ + return 1; \ + } \ + } + +#define C_DEFAULT_MTU 1280 +#define C_DEFAULT_INTERFACE "eth0" +#define C_DEFAULT_PREFIX "64:ff9b::" + +/** + * Configuration file parser. + * + * @param config_file Configuration file (with path) to parse + * @param cmtu Pointer to variable where to save MTU + * @param oto One-time configuration options (used only + * locally to init other things) + * @param init 0 or 1, whether or not to initialize + * configuration with defaults + */ +int cfg_parse(const char *config_file, unsigned short *cmtu, + struct s_cfg_opts *oto, unsigned char init) +{ + FILE *f; + unsigned int ln = 0; + char c; + + unsigned short opt_len, wht_len, val_len; + char tmp_opt[32], tmp_val[128]; + + /* set defaults */ + *cmtu = C_DEFAULT_MTU; + /* TODO: get automatically the first available interface */ + strncpy(oto->interface, C_DEFAULT_INTERFACE, sizeof(oto->interface)); + strncpy(oto->prefix, C_DEFAULT_PREFIX, sizeof(oto->prefix)); + oto->ipv4_address[0] = '\0'; + + f = fopen(config_file, "r"); + + if (f == NULL) { + /* set defaults */ + log_warn("Configuration file %s doesn't exist, using defaults", + config_file); + + if (init) { + log_error("IPv4 address unconfigured! Exiting"); + exit(1); + } + + return 0; + } + + while (c = getc(f), !feof(f)) { + ln++; + + /* comments */ + if (c == '#') { + /* skip this line */ + while (c = getc(f), c != '\n'); + + continue; + } + + /* empty lines */ + if (c == '\n') { + continue; + } + + /* option is only of small letters */ + if (c < 'a' || c > 'z') { + SYNTAX_ERROR(config_file, ln, 0, init); + } + + /* read option */ + for (opt_len = 0; c != ' ' && c != '\t'; opt_len++, + c = getc(f)) { + if (feof(f) || !((c >= 'a' && c <= 'z') || c == '_' || + (c >= '0' && c <= '9'))) { + SYNTAX_ERROR(config_file, ln, opt_len, init); + } + + if (opt_len < 32 - 1) { + tmp_opt[opt_len] = c; + } else { + SYNTAX_ERROR(config_file, ln, opt_len, init); + } + } + tmp_opt[opt_len] = '\0'; + + /* skip white space */ + for (wht_len = 0; c == ' ' || c == '\t'; wht_len++, + c = getc(f)) { + if (feof(f)) { + SYNTAX_ERROR(config_file, ln, opt_len + wht_len, + init); + } + } + + /* read value */ + for (val_len = 0; c != ' ' && c != '\t' && c != '\n'; val_len++, + c = getc(f)) { + if (feof(f)) { + SYNTAX_ERROR(config_file, ln, opt_len, init); + } + + if (val_len < 128 - 1) { + tmp_val[val_len] = c; + } else { + SYNTAX_ERROR(config_file, ln, opt_len, init); + } + } + tmp_val[val_len] = '\0'; + + /* skip rest of this line */ + if (c != '\n') { + while (c = getc(f), c != '\n'); + } + + /* recognize the option */ + if (!strcmp(tmp_opt, "mtu")) { + *cmtu = atoi(tmp_val); + if (*cmtu > MAX_MTU) { + log_warn("MTU setting is over maximum (%d), " + "falling to default value (%d)", + MAX_MTU, C_DEFAULT_MTU); + *cmtu = C_DEFAULT_MTU; + } + } else if (!strcmp(tmp_opt, "interface")) { + strncpy(oto->interface, tmp_val, sizeof(oto->interface)); + } else if (!strcmp(tmp_opt, "prefix")) { + strncpy(oto->prefix, tmp_val, sizeof(oto->prefix)); + } else if (!strcmp(tmp_opt, "ipv4_address")) { + if (val_len < sizeof(oto->ipv4_address)) { + strncpy(oto->ipv4_address, tmp_val, sizeof(oto->ipv4_address)); + } else { + SYNTAX_ERROR(config_file, ln, opt_len + wht_len, init); + } + } else { + log_error("Unknown configuration option"); + SYNTAX_ERROR(config_file, ln, 0, init); + } + } + + fclose(f); + + if (init && oto->ipv4_address[0] == '\0') { + log_error("IPv4 address unconfigured! Exiting"); + exit(1); + } + + return 0; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..0e2b56c --- /dev/null +++ b/src/config.h @@ -0,0 +1,31 @@ +/* + * WrapSix + * Copyright (C) 2008-2013 xHire + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CONFIG_H +#define CONFIG_H + +struct s_cfg_opts { + char interface[128]; + char prefix[128]; + char ipv4_address[16]; +}; + +int cfg_parse(const char *config_file, unsigned short *cmtu, + struct s_cfg_opts *oto, unsigned char init); + +#endif /* CONFIG_H */ diff --git a/src/icmp.c b/src/icmp.c index 4788211..f81b09c 100644 --- a/src/icmp.c +++ b/src/icmp.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2013 Michal Zima + * Copyright (C) 2008-2013 xHire * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,7 +64,7 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, unsigned char *icmp_data; struct s_nat *connection; unsigned short orig_checksum; - unsigned char packet[MTU + sizeof(struct s_ethernet)]; + unsigned char packet[PACKET_BUFFER]; unsigned short new_len = sizeof(struct s_ethernet) + sizeof(struct s_ipv6); @@ -119,15 +119,15 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, icmp->type = ICMPV6_ECHO_REPLY; /* copy the payload data */ - if (payload_size < MTU - sizeof(struct s_ipv6)) { + if (payload_size < mtu - sizeof(struct s_ipv6)) { memcpy(&packet[new_len], payload, payload_size); icmp = (struct s_icmp *) &packet[new_len]; new_len += payload_size; } else { - memcpy(&packet[new_len], payload, MTU - + memcpy(&packet[new_len], payload, mtu - sizeof(struct s_ipv6)); icmp = (struct s_icmp *) &packet[new_len]; - new_len += MTU - sizeof(struct s_ipv6); + new_len += mtu - sizeof(struct s_ipv6); } break; @@ -174,9 +174,9 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, if (ntohs(*icmp_extra_s) < 68) { *icmp_extra = htonl( *icmp_extra_s + 20 < - MTU ? (unsigned int) + mtu ? (unsigned int) *icmp_extra_s + 20 : - MTU); + (unsigned int) mtu); } else { /* RFC1191 */ /* NOTE: >= would cause infinite @@ -1063,10 +1063,10 @@ int sub_icmp4_error(unsigned char *payload, unsigned short payload_size, /* copy payload, aligned to MTU */ /* we can afford to use full MTU instead of just 1280 B as admin * warrants this to us */ - if (payload_size > MTU + sizeof(struct s_ethernet) - *packet_len) { + if (payload_size > mtu + sizeof(struct s_ethernet) - *packet_len) { memcpy(&packet[*packet_len], payload, - MTU + sizeof(struct s_ethernet) - *packet_len); - *packet_len = MTU; + mtu + sizeof(struct s_ethernet) - *packet_len); + *packet_len = mtu; } else { memcpy(&packet[*packet_len], payload, payload_size); *packet_len += payload_size; diff --git a/src/tcp.c b/src/tcp.c index b178098..2b257f7 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2013 Michal Zima + * Copyright (C) 2008-2013 xHire * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -199,8 +199,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, /* allocate enough memory for translated packet */ if ((packet = (unsigned char *) malloc( - payload_size > MTU - sizeof(struct s_ipv6) ? - MTU + sizeof(struct s_ethernet) : + payload_size > mtu - sizeof(struct s_ipv6) ? + mtu + sizeof(struct s_ethernet) : sizeof(struct s_ethernet) + sizeof(struct s_ipv6) + payload_size)) == NULL) { log_error("Lack of free memory"); @@ -233,9 +233,9 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, connection->ipv6_port_src); /* fragment it or not? */ - if (payload_size > MTU - sizeof(struct s_ipv6)) { + if (payload_size > mtu - sizeof(struct s_ipv6)) { /* 1st fragments' payload size must be 8-byte aligned */ - #define FRAGMENT_LEN (((MTU - sizeof(struct s_ipv6) - \ + #define FRAGMENT_LEN (((mtu - sizeof(struct s_ipv6) - \ sizeof(struct s_ipv6_fragment)) / 8) * 8) /* fill in missing IPv6 header fields */ @@ -341,9 +341,9 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, /* allocate enough memory for translated packet */ if ((packet = (unsigned char *) malloc( - payload_size > MTU - sizeof(struct s_ipv6) - + payload_size > mtu - sizeof(struct s_ipv6) - sizeof(struct s_ipv6_fragment) ? - MTU + sizeof(struct s_ethernet) : + mtu + sizeof(struct s_ethernet) : sizeof(struct s_ethernet) + sizeof(struct s_ipv6) + sizeof(struct s_ipv6_fragment) + payload_size)) == NULL) { log_error("Lack of free memory"); @@ -374,7 +374,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, frag->id = htonl(htons(ip4->id)); /* fragment the fragment or not? */ - if (payload_size > MTU - sizeof(struct s_ipv6) - + if (payload_size > mtu - sizeof(struct s_ipv6) - sizeof(struct s_ipv6_fragment)) { /* fill in missing IPv6 header fields */ ip6->len = htons(FRAGMENT_LEN + @@ -391,7 +391,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, payload, FRAGMENT_LEN); /* send translated packet */ - transmit_raw(packet, sizeof(struct s_ethernet) + MTU); + transmit_raw(packet, sizeof(struct s_ethernet) + mtu); /* create the second fragment */ ip6->len = htons(payload_size + diff --git a/src/wrapper.c b/src/wrapper.c index f735a35..7cf6458 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2013 Michal Zima + * Copyright (C) 2008-2013 xHire * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +31,10 @@ #include /* close */ #include "arp.h" +#ifdef HAVE_CONFIG_H +#include "autoconfig.h" +#endif /* HAVE_CONFIG_H */ +#include "config.h" #include "ethernet.h" #include "ipv4.h" #include "ipv6.h" @@ -40,13 +44,11 @@ #include "wrapper.h" /* +++ CONFIGURATION +++ */ -#define INTERFACE "eth0" -#define PREFIX "64:ff9b::" -#define IPV4_ADDR "192.168.0.111" #define HOST_IPV6_ADDR "fd77::1:0:1" #define HOST_IPV4_ADDR "192.168.0.19" /* --- CONFIGURATION --- */ +unsigned short mtu; struct ifreq interface; struct s_mac_addr mac; @@ -60,6 +62,8 @@ int process(char *packet); int main(int argc, char **argv) { + struct s_cfg_opts cfg; + struct packet_mreq pmr; struct ethtool_value ethtool; @@ -72,6 +76,18 @@ int main(int argc, char **argv) log_info(PACKAGE_STRING " is starting"); + /* load configuration */ + if (argc == 1) { + cfg_parse(SYSCONFDIR "/wrapsix.conf", &mtu, &cfg, 1); + } else { + cfg_parse(argv[1], &mtu, &cfg, 1); + } + + log_info("Using: interface %s", cfg.interface); + log_info(" prefix %s", cfg.prefix); + log_info(" MTU %d", mtu); + log_info(" IPv4 address %s", cfg.ipv4_address); + /* initialize the socket for sniffing */ if ((sniff_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) { @@ -80,9 +96,9 @@ int main(int argc, char **argv) } /* get the interface */ - strncpy(interface.ifr_name, INTERFACE, IFNAMSIZ); + strncpy(interface.ifr_name, cfg.interface, IFNAMSIZ); if (ioctl(sniff_sock, SIOCGIFINDEX, &interface) == -1) { - log_error("Unable to get the interface"); + log_error("Unable to get the interface %s", cfg.interface); return 1; } @@ -128,10 +144,10 @@ int main(int argc, char **argv) inet_pton(AF_INET6, "ff02::1:ff00:0", &ndp_multicast_addr); /* compute binary IPv6 address of WrapSix prefix */ - inet_pton(AF_INET6, PREFIX, &wrapsix_ipv6_prefix); + inet_pton(AF_INET6, cfg.prefix, &wrapsix_ipv6_prefix); /* compute binary IPv4 address of WrapSix */ - inet_pton(AF_INET, IPV4_ADDR, &wrapsix_ipv4_addr); + inet_pton(AF_INET, cfg.ipv4_address, &wrapsix_ipv4_addr); /* compute binary IPv6 address of WrapSix host */ inet_pton(AF_INET6, HOST_IPV6_ADDR, &host_ipv6_addr); diff --git a/src/wrapper.h b/src/wrapper.h index 94c495f..c02f8bc 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2012 Michal Zima + * Copyright (C) 2008-2013 xHire * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,11 +22,12 @@ #include "ipv4.h" #include "ipv6.h" -/* +++ CONFIGURE +++ */ -#define MTU 1280 /* MTU on IPv6 side */ +/* +++ INTERNAL CONFIGURATION +++ */ +#define MAX_MTU 1500 /* maximum MTU on IPv6 side */ #define PACKET_BUFFER 1514 /* buffer for any packet */ -/* --- CONFIGURE --- */ +/* --- INTERNAL CONFIGURATION --- */ +extern unsigned short mtu; extern struct ifreq interface; extern struct s_mac_addr mac; extern struct s_ipv6_addr ndp_multicast_addr;