diff --git a/NEWS b/NEWS
index 4cdde35..e64dd61 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
+WrapSix 0.2.1
+=============
+- custom configuration files and some autodetection
+
WrapSix 0.2.0
=============
-
- completely rewritten from scratch, but without DNS64 for now
- dropped all external dependencies
- cleaner design & implementation with emphasis on CPU & memory efficiency
diff --git a/src/config.c b/src/config.c
index fb69b2f..87b716b 100644
--- a/src/config.c
+++ b/src/config.c
@@ -16,11 +16,16 @@
* along with this program. If not, see .
*/
-#include
-#include
-#include
+#include /* inet_pton */
+#include /* struct ifaddrs, getifaddrs, freeifaddrs */
+#include /* getnameinfo, NI_NUMERICHOST */
+#include /* FILE, fopen, getc, feof, fclose, perror */
+#include /* exit */
+#include /* strcmp, strncpy */
#include "config.h"
+#include "ipv4.h"
+#include "ipv6.h"
#include "log.h"
#include "wrapper.h"
@@ -36,9 +41,10 @@
}
#define C_DEFAULT_MTU 1280
-#define C_DEFAULT_INTERFACE "eth0"
#define C_DEFAULT_PREFIX "64:ff9b::"
+void cfg_guess_interface(char *cinterface);
+
/**
* Configuration file parser.
*
@@ -48,6 +54,12 @@
* locally to init other things)
* @param init 0 or 1, whether or not to initialize
* configuration with defaults
+ *
+ * @return 0 for success
+ * @return 1 for failure in case of some syntax error when reloading
+ * configuration
+ * @return exit with code 1 in case of some syntax error when initializing
+ * configuration
*/
int cfg_parse(const char *config_file, unsigned short *cmtu,
struct s_cfg_opts *oto, unsigned char init)
@@ -61,15 +73,14 @@ int cfg_parse(const char *config_file, unsigned short *cmtu,
/* set defaults */
*cmtu = C_DEFAULT_MTU;
- /* TODO: get automatically the first available interface */
- strncpy(oto->interface, C_DEFAULT_INTERFACE, sizeof(oto->interface));
+ oto->interface[0] = '\0';
+ cfg_guess_interface(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);
@@ -181,3 +192,136 @@ int cfg_parse(const char *config_file, unsigned short *cmtu,
return 0;
}
+
+/**
+ * Configures host IP addresses for usage in ICMP error messages. If some or
+ * both is not available, defaults are used.
+ *
+ * As a default in case of IPv4 is used IPv4 address assigned to WrapSix in
+ * configuration, in case of IPv6 is used made up address from default NAT64
+ * prefix -- WrapSix itself cannot act as a host so it doesn't matter.
+ *
+ * @param cinterface Name of the interface WrapSix sits on
+ * @param ipv6_addr Where to save host IPv6 address
+ * @param ipv4_addr Where to save host IPv4 address
+ * @param default_ipv4_addr IPv4 address assigned to WrapSix
+ *
+ * @return 0 for success
+ * @return 1 for failure
+ */
+int cfg_host_ips(char *cinterface, struct s_ipv6_addr *ipv6_addr,
+ struct s_ipv4_addr *ipv4_addr, char *default_ipv4_addr)
+{
+ struct ifaddrs *ifaddr, *ifa;
+ /* 0x01 IPv6 from WrapSix' interface
+ * 0x02 IPv4 from WrapSix' interface
+ * 0x04 IPv6 from another interface
+ * 0x08 IPv4 from another interface
+ */
+ char found = 0;
+ char ip_text[40];
+
+ if (getifaddrs(&ifaddr) == -1) {
+ perror("getifaddrs");
+ return 1;
+ }
+
+ /* Walk through linked list, maintaining head pointer so we can free
+ * list later */
+
+ /* first try to get addresses from the interface */
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL) {
+ continue;
+ }
+
+ if (!strcmp(ifa->ifa_name, cinterface)) {
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ !(found & 0x01)) {
+ found |= 0x01;
+ getnameinfo(ifa->ifa_addr,
+ sizeof(struct sockaddr_in6),
+ ip_text, sizeof(ip_text), NULL, 0,
+ NI_NUMERICHOST);
+ inet_pton(AF_INET6, ip_text, ipv6_addr);
+ } else if (ifa->ifa_addr->sa_family == AF_INET &&
+ !(found & 0x02)) {
+ found |= 0x02;
+ getnameinfo(ifa->ifa_addr,
+ sizeof(struct sockaddr_in),
+ ip_text, sizeof(ip_text), NULL, 0,
+ NI_NUMERICHOST);
+ inet_pton(AF_INET, ip_text, ipv4_addr);
+ }
+ } else { /* look for addresses on other interfaces too */
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ !(found & 0x05)) {
+ found |= 0x04;
+ getnameinfo(ifa->ifa_addr,
+ sizeof(struct sockaddr_in6),
+ ip_text, sizeof(ip_text), NULL, 0,
+ NI_NUMERICHOST);
+ inet_pton(AF_INET6, ip_text, ipv6_addr);
+ } else if (ifa->ifa_addr->sa_family == AF_INET &&
+ !(found & 0x0a)) {
+ found |= 0x08;
+ getnameinfo(ifa->ifa_addr,
+ sizeof(struct sockaddr_in),
+ ip_text, sizeof(ip_text), NULL, 0,
+ NI_NUMERICHOST);
+ inet_pton(AF_INET, ip_text, ipv4_addr);
+ }
+ }
+
+ if ((found & 0x03) == 0x03) {
+ break;
+ }
+ }
+
+ /* no IPv4 address -> use default */
+ if (!(found & 0x0a)) {
+ inet_pton(AF_INET, default_ipv4_addr, ipv4_addr);
+ }
+
+ /* IPv6 default? huh... but we can't work without host IPv6 address */
+ if (!(found & 0x05)) {
+ /* FUN: try to decode it ;c) */
+ inet_pton(AF_INET6, "64:ff9b::E7ad:514", ipv6_addr);
+ }
+
+ freeifaddrs(ifaddr);
+
+ return 0;
+}
+
+/**
+ * Gets name of first non-loopback network interface.
+ *
+ * @param cinterface Where to save the interface name
+ */
+void cfg_guess_interface(char *cinterface)
+{
+ struct ifaddrs *ifaddr, *ifa;
+
+ if (getifaddrs(&ifaddr) == -1) {
+ perror("getifaddrs");
+ return;
+ }
+
+ /* Walk through linked list, maintaining head pointer so we can free
+ * list later */
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL) {
+ continue;
+ }
+
+ /* skip loopback */
+ if (strcmp(ifa->ifa_name, "lo")) {
+ strncpy(cinterface, ifa->ifa_name, sizeof(cinterface));
+ break;
+ }
+ }
+
+ freeifaddrs(ifaddr);
+}
diff --git a/src/config.h b/src/config.h
index 0e2b56c..54a2fde 100644
--- a/src/config.h
+++ b/src/config.h
@@ -19,6 +19,9 @@
#ifndef CONFIG_H
#define CONFIG_H
+#include "ipv4.h"
+#include "ipv6.h"
+
struct s_cfg_opts {
char interface[128];
char prefix[128];
@@ -27,5 +30,7 @@ struct s_cfg_opts {
int cfg_parse(const char *config_file, unsigned short *cmtu,
struct s_cfg_opts *oto, unsigned char init);
+int cfg_host_ips(char *cinterface, struct s_ipv6_addr *ipv6_addr,
+ struct s_ipv4_addr *ipv4_addr, char *default_ipv4_addr);
#endif /* CONFIG_H */
diff --git a/src/wrapper.c b/src/wrapper.c
index 7cf6458..377b01f 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -43,11 +43,6 @@
#include "transmitter.h"
#include "wrapper.h"
-/* +++ CONFIGURATION +++ */
-#define HOST_IPV6_ADDR "fd77::1:0:1"
-#define HOST_IPV4_ADDR "192.168.0.19"
-/* --- CONFIGURATION --- */
-
unsigned short mtu;
struct ifreq interface;
@@ -88,6 +83,22 @@ int main(int argc, char **argv)
log_info(" MTU %d", mtu);
log_info(" IPv4 address %s", cfg.ipv4_address);
+ /* get host IP addresses */
+ if (cfg_host_ips(cfg.interface, &host_ipv6_addr, &host_ipv4_addr,
+ cfg.ipv4_address)) {
+ log_error("Unable to get host IP addresses");
+ return 1;
+ }
+ /* using block because of the temporary variable */
+ {
+ char ip_text[40];
+
+ inet_ntop(AF_INET, &host_ipv4_addr, ip_text, sizeof(ip_text));
+ log_info(" host IPv4 address %s", ip_text);
+ inet_ntop(AF_INET6, &host_ipv6_addr, ip_text, sizeof(ip_text));
+ log_info(" host IPv6 address %s", ip_text);
+ }
+
/* initialize the socket for sniffing */
if ((sniff_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) ==
-1) {
@@ -149,12 +160,6 @@ int main(int argc, char **argv)
/* compute binary IPv4 address of WrapSix */
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);
-
- /* compute binary IPv4 address of WrapSix host */
- inet_pton(AF_INET, HOST_IPV4_ADDR, &host_ipv4_addr);
-
/* initiate sending socket */
if (transmission_init()) {
log_error("Unable to initiate sending socket");
diff --git a/wrapsix.conf b/wrapsix.conf
index cdbf68f..ea39146 100644
--- a/wrapsix.conf
+++ b/wrapsix.conf
@@ -9,9 +9,9 @@
# Don't enter information about prefix length (/96).
#prefix 64:ff9b::
-# WrapSix automatically detects first interface and uses it. Use this option to
-# run WrapSix on different interace.
-interface eth0
+# WrapSix automatically detects first (non-loopback) interface and uses it. Use
+# this option to run WrapSix on different interace.
+#interface eth0
# Unassigned IPv4 address for sole usage by WrapSix. Even the OS mustn't have it
# assigned.