22 * gre.c - userspace GRE tunnel
33 *
44 * Copyright (C) 2015 - 2017, Xiaoxiao <[email protected] > 5+ * Copyright (C) 2019, Mikael Magnusson <[email protected] > 56 *
67 * This program is free software; you can redistribute it and/or modify
78 * it under the terms of the GNU General Public License as published by
2122#include <errno.h>
2223#include <fcntl.h>
2324#include <linux/if_tun.h>
25+ #include <net/ethernet.h>
2426#include <net/if.h>
27+ #include <netdb.h>
2528#include <netinet/in.h>
2629#include <pwd.h>
2730#include <stdint.h>
3740
3841static int tun ;
3942static int sock ;
40- static struct sockaddr_in remote ;
43+ static struct sockaddr_storage remote ;
44+ static size_t remote_len ;
4145
4246uint8_t buf [4096 ];
4347
4448static void gre_cb (void );
49+ static void gre_ipv4 (const uint8_t * buf , int n );
50+ static void gre_ipv6 (const uint8_t * buf , int n , const struct sockaddr_in6 * src );
51+ static void gre_any (const uint8_t * buf , int n );
4552static int tun_cb (void );
4653static int tun_new (const char * dev );
4754static int setnonblock (int fd );
4855static int runas (const char * user );
4956static int daemonize (void );
57+ static int inet_addr_storage (const char * cp , struct sockaddr_storage * sp , size_t * sp_len );
5058
5159int main (int argc , char * * argv )
5260{
@@ -65,35 +73,28 @@ int main(int argc, char **argv)
6573 return EXIT_FAILURE ;
6674 }
6775
68- sock = socket (AF_INET , SOCK_RAW , IPPROTO_GRE );
69- if (sock < 0 )
76+ struct sockaddr_storage local ;
77+ size_t local_len = 0 ;
78+ if (inet_addr_storage (argv [3 ], & local , & local_len ))
7079 {
71- perror ( "socket " );
80+ fprintf ( stderr , "bad local address\n " );
7281 return EXIT_FAILURE ;
7382 }
7483
75- struct sockaddr_in local ;
76- local .sin_family = AF_INET ;
77- local .sin_port = htons (IPPROTO_GRE );
78- local .sin_addr .s_addr = inet_addr (argv [3 ]);
79- if (local .sin_addr .s_addr == INADDR_NONE )
84+ sock = socket (local .ss_family , SOCK_RAW , IPPROTO_GRE );
85+ if (sock < 0 )
8086 {
81- fprintf ( stderr , "bad local address\n " );
87+ perror ( "socket " );
8288 return EXIT_FAILURE ;
8389 }
84- else
90+
91+ if (bind (sock , (struct sockaddr * )& local , local_len ) != 0 )
8592 {
86- if (bind (sock , (struct sockaddr * )& local , sizeof (local )) != 0 )
87- {
88- perror ("bind" );
89- return EXIT_FAILURE ;
90- }
93+ perror ("bind" );
94+ return EXIT_FAILURE ;
9195 }
9296
93- remote .sin_family = AF_INET ;
94- remote .sin_port = htons (IPPROTO_GRE );
95- remote .sin_addr .s_addr = inet_addr (argv [2 ]);
96- if (remote .sin_addr .s_addr == INADDR_NONE )
97+ if (inet_addr_storage (argv [2 ], & remote , & remote_len ))
9798 {
9899 fprintf (stderr , "bad remote address\n" );
99100 return EXIT_FAILURE ;
@@ -142,46 +143,81 @@ int main(int argc, char **argv)
142143
143144static void gre_cb (void )
144145{
145- int ihl ; // IP header length
146146 int n ;
147+ struct sockaddr_storage src ;
148+ size_t src_len = sizeof (src );
147149
148- n = recv (sock , buf , sizeof (buf ), 0 );
150+ memset (& src , 0 , src_len );
151+ n = recvfrom (sock , buf , sizeof (buf ), 0 , (struct sockaddr * )& src , & src_len );
149152 if (n < 0 )
150153 {
151154 perror ("recv" );
152155 return ;
153156 }
157+
158+ switch (remote .ss_family ) {
159+ case AF_INET : gre_ipv4 (buf , n ); break ;
160+ case AF_INET6 : gre_ipv6 (buf , n , (const struct sockaddr_in6 * )& src ); break ;
161+ }
162+ }
163+
164+ static void gre_ipv4 (const uint8_t * buf , int n )
165+ {
166+ int ihl ; // IP header length
167+
154168 ihl = 4 * (buf [0 ] & 0x0f );
155169 if (ihl > 60 || ihl < 20 )
156170 {
157171 printf ("IPv4 header too long\n" );
158172 return ;
159173 }
160174 // check source IPv4 address
161- if (* (uint32_t * )(buf + 12 ) != remote .sin_addr .s_addr )
175+ const struct sockaddr_in * remote_in = (const struct sockaddr_in * )& remote ;
176+ if (* (uint32_t * )(buf + 12 ) != remote_in -> sin_addr .s_addr )
162177 {
163178 return ;
164179 }
165180
181+ gre_any (buf + ihl , n - ihl );
182+ }
183+
184+ static void gre_ipv6 (const uint8_t * buf , int n , const struct sockaddr_in6 * src )
185+ {
186+ if (n < 40 )
187+ {
188+ return ;
189+ }
190+ // check source IPv6 address
191+ const struct sockaddr_in6 * remote_in6 = (const struct sockaddr_in6 * )& remote ;
192+ if (memcmp (src -> sin6_addr .s6_addr , remote_in6 -> sin6_addr .s6_addr , 16 ) != 0 )
193+ {
194+ return ;
195+ }
196+
197+ gre_any (buf , n );
198+ }
199+
200+ static void gre_any (const uint8_t * buf , int n )
201+ {
166202 // parse GRE header
167- if (* (uint16_t * )(buf + ihl ) != 0 )
203+ if (* (uint16_t * )(buf ) != 0 )
168204 {
169205 return ;
170206 }
171- uint16_t protocol = ntohs (* (uint16_t * )(buf + ihl + 2 ));
172- if (protocol != 0x0800 )
207+ uint16_t protocol = ntohs (* (uint16_t * )(buf + 2 ));
208+ if (protocol != ETHERTYPE_IP && protocol != ETHERTYPE_IPV6 )
173209 {
174210 return ;
175211 }
176212
177- write (tun , buf + ihl + 4 , n - ihl - 4 );
213+ write (tun , buf , n );
178214}
179215
180216static int tun_cb (void )
181217{
182218 int n ;
183219
184- n = read (tun , buf + 4 , sizeof (buf ) - 4 );
220+ n = read (tun , buf , sizeof (buf ));
185221 if (n < 0 )
186222 {
187223 int err = errno ;
@@ -191,9 +227,14 @@ static int tun_cb(void)
191227
192228 return 0 ;
193229 }
194- * (uint16_t * )(buf ) = 0 ;
195- * (uint16_t * )(buf + 2 ) = htons (0x0800 );
196- sendto (sock , buf , n + 4 , 0 , (struct sockaddr * )& remote , sizeof (struct sockaddr ));
230+ buf [0 ] = 0 ;
231+ buf [1 ] = 0 ;
232+ uint16_t proto = ntohs (* (uint16_t * )(buf + 2 ));
233+ if (proto != ETHERTYPE_IP && proto != ETHERTYPE_IPV6 )
234+ {
235+ return 0 ;
236+ }
237+ sendto (sock , buf , n , 0 , (struct sockaddr * )& remote , remote_len );
197238 return 0 ;
198239}
199240
@@ -210,7 +251,7 @@ static int tun_new(const char *dev)
210251
211252 bzero (& ifr , sizeof (struct ifreq ));
212253
213- ifr .ifr_flags = IFF_TUN | IFF_NO_PI ;
254+ ifr .ifr_flags = IFF_TUN ;
214255 if (* dev != '\0' )
215256 {
216257 strncpy (ifr .ifr_name , dev , IFNAMSIZ );
@@ -284,3 +325,35 @@ static int daemonize(void)
284325
285326 return 0 ;
286327}
328+
329+ static int inet_addr_storage (const char * cp , struct sockaddr_storage * sp , size_t * sp_len )
330+ {
331+ struct addrinfo hints ;
332+ struct addrinfo * result = NULL ;
333+ int res ;
334+
335+ memset (& hints , 0 , sizeof (hints ));
336+ hints .ai_family = AF_UNSPEC ;
337+ hints .ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG ;
338+ res = getaddrinfo (cp , NULL , & hints , & result );
339+ if (res != 0 ) {
340+ fprintf (stderr , "getaddrinfo: %s\n" , gai_strerror (res ));
341+ return -1 ;
342+ }
343+
344+ memcpy (sp , result -> ai_addr , result -> ai_addrlen );
345+ * sp_len = result -> ai_addrlen ;
346+
347+ freeaddrinfo (result );
348+ result = NULL ;
349+
350+ if (sp -> ss_family == AF_INET ) {
351+ struct sockaddr_in * sin = (struct sockaddr_in * )sp ;
352+ sin -> sin_port = htons (IPPROTO_GRE );
353+ } else if (sp -> ss_family == AF_INET6 ) {
354+ struct sockaddr_in6 * sin = (struct sockaddr_in6 * )sp ;
355+ sin -> sin6_port = htons (IPPROTO_GRE );
356+ }
357+
358+ return 0 ;
359+ }
0 commit comments