55#include <sys/socket.h>
59#define TUN_PRIO CONTIKI_VERBOSE_PRIO + 30
63#define LOG_MODULE "Tun6"
64#define LOG_LEVEL LOG_LEVEL_WARN
68#define DEFAULT_TUN "utun10"
70#define DEFAULT_TUN "tun0"
73#define DEFAULT_PREFIX "fd00::1/64"
74static const char *config_ipaddr = DEFAULT_PREFIX;
75static char config_tundev[IFNAMSIZ + 1] = DEFAULT_TUN;
76static void (* tun_input_callback)(void);
79#define MIN_MTU_SIZE 1500
80static int config_mtu = MIN_MTU_SIZE;
84static int set_fd(fd_set *rset, fd_set *wset);
85static void handle_fd(fd_set *rset, fd_set *wset);
86static const struct select_callback tun_select_callback = {
91static int ssystem(
const char *fmt, ...)
92 __attribute__((__format__ (__printf__, 1, 2)));
95ssystem(const
char *fmt, ...)
100 vsnprintf(cmd,
sizeof(cmd), fmt, ap);
102 LOG_INFO(
"%s\n", cmd);
109set_default_prefix(
const char *prefix)
111 char *
ipaddr = strdup(prefix);
116 bool success =
false;
117 char *s = strchr(
ipaddr,
'/');
119 uip_ip6addr_t prefix_addr;
131tun6_net_get_prefix(
void)
133 return config_ipaddr;
137tun6_net_set_prefix(
const char *prefix)
139 if(!set_default_prefix(prefix)) {
140 LOG_WARN(
"Failed to set default prefix %s\n", prefix);
142 config_ipaddr = prefix;
146tun6_net_get_tun_name(
void)
148 return config_tundev;
152tun6_net_set_tun_name(
const char *tun_name)
155 if(strncmp(
"/dev/", tun_name, 5) == 0) {
158 strncpy(config_tundev, tun_name,
sizeof(config_tundev) - 1);
159 config_tundev[
sizeof(config_tundev) - 1] =
'\0';
163tun6_net_get_mtu(
void)
169tun6_net_set_mtu(
int mtu_size)
171 if(mtu_size < MIN_MTU_SIZE) {
172 LOG_WARN(
"ignoring too small MTU size %d, using %d\n",
173 mtu_size, config_mtu);
175 config_mtu = mtu_size;
180tun_dev_callback(
const char *optarg)
182 tun6_net_set_tun_name(optarg);
187 "name of tun interface (default: " DEFAULT_TUN
")\n");
191prefix_callback(
const char *optarg)
193 tun6_net_set_prefix(optarg);
196CONTIKI_OPTION(TUN_PRIO + 1, {
"prefix", required_argument, NULL, 0 },
198 "Subnet prefix (default: " DEFAULT_PREFIX
")\n");
201mtu_callback(
const char *optarg)
203 tun6_net_set_mtu(atoi(optarg));
206CONTIKI_OPTION(TUN_PRIO + 2, {
"mtu", required_argument, NULL, 0 },
207 mtu_callback,
"interface MTU size\n");
212#define TMPBUFSIZE 128
214 char buf[TMPBUFSIZE];
216 strcpy(buf,
"ifconfig ");
218 buf[TMPBUFSIZE - 1] =
'\0';
219 strncat(buf, config_tundev, TMPBUFSIZE - strlen(buf) - 1);
220 strncat(buf,
" inet6 ", TMPBUFSIZE - strlen(buf) - 1);
221 strncat(buf, config_ipaddr, TMPBUFSIZE - strlen(buf) - 1);
222 strncat(buf,
" remove", TMPBUFSIZE - strlen(buf) - 1);
226 strcpy(buf,
"ifconfig ");
228 buf[TMPBUFSIZE - 1] =
'\0';
229 strncat(buf, config_tundev, TMPBUFSIZE - strlen(buf) - 1);
230 strncat(buf,
" down", TMPBUFSIZE - strlen(buf) - 1);
235 system(
"sysctl -w net.ipv6.conf.all.forwarding=1");
238 strcpy(buf,
"netstat -nr"
239 " | awk '{ if ($2 == \"");
240 buf[TMPBUFSIZE - 1] =
'\0';
241 strncat(buf, config_tundev, TMPBUFSIZE - strlen(buf) - 1);
242 strncat(buf,
"\") print \"route delete -net \"$1; }'"
243 " | sh", TMPBUFSIZE - strlen(buf) - 1);
251 const char *prefix =
"signal ";
253 signo == SIGHUP ?
"HUP\n" : signo == SIGTERM ?
"TERM\n" :
"INT\n";
254 write(fileno(stderr), prefix, strlen(prefix));
255 write(fileno(stderr), sig, strlen(sig));
264 ssystem(
"ifconfig %s inet `hostname` mtu %d up", config_tundev, config_mtu);
265 ssystem(
"ifconfig %s add %s", config_tundev, config_ipaddr);
266#elif defined(__APPLE__)
267 ssystem(
"ifconfig %s inet6 mtu %d up", config_tundev, config_mtu);
268 ssystem(
"ifconfig %s inet6 %s add", config_tundev, config_ipaddr );
269 ssystem(
"sysctl -w net.inet6.ip6.forwarding=1");
271 ssystem(
"ifconfig %s inet `hostname` %s mtu %d up", config_tundev, config_ipaddr, config_mtu);
272 ssystem(
"sysctl -w net.inet.ip.forwarding=1");
276 ssystem(
"ifconfig %s\n", config_tundev);
281#include <linux/if_tun.h>
289 LOG_INFO(
"Opening tun interface %s\n", config_tundev);
291 if((fd = open(
"/dev/net/tun", O_RDWR)) < 0) {
296 memset(&ifr, 0,
sizeof(ifr));
301 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
302 if(*config_tundev !=
'\0') {
303 strncpy(ifr.ifr_name, config_tundev,
sizeof(ifr.ifr_name) - 1);
304 ifr.ifr_name[
sizeof(ifr.ifr_name) - 1] =
'\0';
307 if((err = ioctl(fd, TUNSETIFF, (
void *)&ifr)) < 0) {
313 LOG_INFO(
"Using '%s' as '%s'\n", config_tundev, ifr.ifr_name);
314 strncpy(config_tundev, ifr.ifr_name,
sizeof(config_tundev) - 1);
315 config_tundev[
sizeof(config_tundev) - 1] =
'\0';
318#elif defined __APPLE__
319#include <sys/sys_domain.h>
320#include <sys/kern_control.h>
321#include <net/if_utun.h>
333 if(sscanf(config_tundev,
"utun%u", &tunif) != 1 || tunif >= UINT8_MAX) {
334 fprintf(stderr,
"tun_alloc: invalid utun interface specified: %s\n", config_tundev);
338 LOG_INFO(
"Opening tun interface %s\n", config_tundev);
340 struct ctl_info ctl_info = { 0 };
341 if(strlcpy(ctl_info.ctl_name, UTUN_CONTROL_NAME,
sizeof(ctl_info.ctl_name)) >=
342 sizeof(ctl_info.ctl_name)) {
343 fprintf(stderr,
"UTUN_CONTROL_NAME too long");
347 int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
349 perror(
"socket(SYSPROTO_CONTROL)");
353 if(ioctl(fd, CTLIOCGINFO, &ctl_info) == -1) {
354 perror(
"ioctl(CTLIOCGINFO)");
359 struct sockaddr_ctl sc;
360 sc.sc_id = ctl_info.ctl_id;
361 sc.sc_len =
sizeof(sc);
362 sc.sc_family = AF_SYSTEM;
363 sc.ss_sysaddr = AF_SYS_CONTROL;
364 sc.sc_unit = tunif + 1;
371 if(connect(fd, (
struct sockaddr *)&sc,
sizeof(sc)) == -1) {
372 perror(
"connect(AF_SYS_CONTROL)");
383 char t[8 +
sizeof(config_tundev)] =
"/dev/";
384 strncat(t, config_tundev,
sizeof(t) - 6);
385 t[
sizeof(t) - 1] =
'\0';
386 LOG_INFO(
"Opening tun interface %s\n", t);
387 return open(t, O_RDWR);
392tun6_net_init(
void (* tun_input)(
void))
397 tun_input_callback = tun_input;
399 setvbuf(stdout, NULL, _IOLBF, 0);
406 LOG_INFO(
"Tun open:%d\n", tunfd);
408 select_set_callback(tunfd, &tun_select_callback);
410 fprintf(stderr,
"opened %s device ``/dev/%s''\n",
411 "tun", config_tundev);
414 signal(SIGHUP, sigcleanup);
415 signal(SIGTERM, sigcleanup);
416 signal(SIGINT, sigcleanup);
422tun6_net_output(uint8_t *data,
int len)
430 u_int32_t type = htonl(AF_INET6);
433 iv[0].iov_base = &type;
434 iv[0].iov_len =
sizeof(type);
435 iv[1].iov_base = data;
438 if(writev(tunfd, iv, 2) != (
sizeof(type) + len)) {
439 err(EXIT_FAILURE,
"tun6_net_output: writev");
442 if(write(tunfd, data, len) != len) {
443 err(EXIT_FAILURE,
"tun6_net_output: write");
451tun6_net_input(uint8_t *data,
int maxlen)
460 if((size = read(tunfd, data, maxlen)) == -1) {
461 err(EXIT_FAILURE,
"tun6_net_input: read");
465#define UTUN_HEADER_LEN 4
467 if(size <= UTUN_HEADER_LEN) {
468 err(EXIT_FAILURE,
"tun6_net_input: read too small");
471 size -= UTUN_HEADER_LEN;
472 memmove(data, data + UTUN_HEADER_LEN, size);
473#undef UTUN_HEADER_LEN
483set_fd(fd_set *rset, fd_set *wset)
494handle_fd(fd_set *rset, fd_set *wset)
501 if(FD_ISSET(tunfd, rset)) {
502 tun_input_callback();
513 LOG_DBG(
"TUN data incoming read:%d\n", size);
521 if(!tun6_net_init(tun_input)) {
522 LOG_WARN(
"Failed to open tun device (you may be lacking permission). Running without network.\n");
527network_output(
const linkaddr_t *localdest)
530 LOG_DBG(
"output: %u bytes to ",
uip_len);
531 LOG_DBG_LLADDR(localdest);
542 LOG_DBG(
"unexpected network input\n");
#define CC_NORETURN
Configure if the C compiler supports functions that are not meant to return e.g.
#define CONTIKI_OPTION(prio,...)
Add a command line option when the compilation unit is present.
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
#define uiplib_ipaddrconv
Convert a textual representation of an IP address to a numerical representation.
void uip_ds6_set_default_prefix(const uip_ip6addr_t *prefix)
Set the Default IPv6 prefix.
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Header file for the logging system.
Include file for the Contiki low-layer network stack (NETSTACK)
The structure of a network driver in Contiki.
Header file for IPv6-related data structures.
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Header file for the uIP TCP/IP stack.
Header file for the IP address manipulation library.