d063b17b5c8511b6cfd1c83bfcb70f648275b2ce
[tinc] / src / ifconfig.c
1 /*
2     ifconfig.c -- Generate platform specific interface configuration commands
3     Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "conf.h"
23 #include "ifconfig.h"
24 #include "subnet.h"
25
26 static long start;
27
28 #ifndef HAVE_MINGW
29 void ifconfig_header(FILE *out) {
30         fprintf(out, "#!/bin/sh\n");
31         start = ftell(out);
32 }
33
34 void ifconfig_dhcp(FILE *out) {
35         fprintf(out, "dhclient -nw \"$INTERFACE\"\n");
36 }
37
38 void ifconfig_dhcp6(FILE *out) {
39         fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n");
40 }
41
42 void ifconfig_slaac(FILE *out) {
43 #ifdef HAVE_LINUX
44         fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n");
45         fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n");
46 #else
47         fprintf(out, "rtsol \"$INTERFACE\" &\n");
48 #endif
49 }
50
51 bool ifconfig_footer(FILE *out) {
52         if(ftell(out) == start) {
53                 fprintf(out, "echo 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
54                 return false;
55         } else {
56 #ifdef HAVE_LINUX
57                 fprintf(out, "ip link set \"$INTERFACE\" up\n");
58 #else
59                 fprintf(out, "ifconfig \"$INTERFACE\" up\n");
60 #endif
61                 return true;
62         }
63 }
64 #else
65 void ifconfig_header(FILE *out) {
66         start = ftell(out);
67 }
68
69 void ifconfig_dhcp(FILE *out) {
70         fprintf(out, "netsh interface ipv4 set address \"%INTERFACE%\" dhcp\n");
71 }
72
73 void ifconfig_dhcp6(FILE *out) {
74         fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
75 }
76
77 void ifconfig_slaac(FILE *out) {
78         // It's the default?
79 }
80
81 bool ifconfig_footer(FILE *out) {
82         return ftell(out) != start;
83 }
84 #endif
85
86 static subnet_t ipv4, ipv6;
87
88 void ifconfig_address(FILE *out, const char *value) {
89         subnet_t subnet = {};
90         char str[MAXNETSTR];
91         if(!str2net(&subnet, value) || !net2str(str, sizeof str, &subnet)) {
92                 fprintf(stderr, "Could not parse Ifconfig statement\n");
93                 return;
94         }
95         switch(subnet.type) {
96                 case SUBNET_IPV4: ipv4 = subnet; break;
97                 case SUBNET_IPV6: ipv6 = subnet; break;
98         }
99 #if defined(HAVE_LINUX)
100         switch(subnet.type) {
101                 case SUBNET_MAC:  fprintf(out, "ip link set \"$INTERFACE\" address %s\n", str); break;
102                 case SUBNET_IPV4: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", str); break;
103                 case SUBNET_IPV6: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", str); break;
104         }
105 #elif defined(HAVE_BSD)
106         switch(subnet.type) {
107                 case SUBNET_MAC:  fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", str); break;
108                 case SUBNET_IPV4: fprintf(out, "ifconfig \"$INTERFACE\" %s\n", str); break;
109                 case SUBNET_IPV6: fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", str); break;
110         }
111 #elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
112         switch(subnet.type) {
113                 case SUBNET_MAC:  fprintf(out, "ip link set \"$INTERFACE\" address %s\n", str); break;
114                 case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 set address \"$INTERFACE\" static %s\n", str); break;
115                 case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 set address \"$INTERFACE\" static %s\n", str); break;
116         }
117 #endif
118 }
119
120 void ifconfig_route(FILE *out, const char *value) {
121         subnet_t subnet = {};
122         char str[MAXNETSTR];
123         if(!str2net(&subnet, value) || !net2str(str, sizeof str, &subnet) || subnet.type == SUBNET_MAC) {
124                 fprintf(stderr, "Could not parse Ifconfig statement\n");
125                 return;
126         }
127 #if defined(HAVE_LINUX)
128         switch(subnet.type) {
129                 case SUBNET_IPV4: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", str); break;
130                 case SUBNET_IPV6: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", str); break;
131         }
132 #elif defined(HAVE_BSD)
133         // BSD route command is silly and doesn't accept an interface name as a destination.
134         char gwstr[MAXNETSTR] = "";
135         switch(subnet.type) {
136                 case SUBNET_IPV4:
137                         if(!ipv4.type) {
138                                 fprintf(stderr, "Route requested but no Ifconfig\n");
139                                 return;
140                         }
141                         net2str(gwstr, sizeof gwstr, &ipv4);
142                         char *p = strchr(gwstr, '/'); if(p) *p = 0;
143                         fprintf(out, "route add %s %s\n", str, gwstr);
144                         break;
145                 case SUBNET_IPV6:
146                         if(!ipv6.type) {
147                                 fprintf(stderr, "Route requested but no Ifconfig\n");
148                                 return;
149                         }
150                         net2str(gwstr, sizeof gwstr, &ipv6);
151                         char *p = strchr(gwstr, '/'); if(p) *p = 0;
152                         fprintf(out, "route add -inet6 %s %s\n", str, gwstr);
153                         break;
154         }
155 #elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
156         switch(subnet.type) {
157                 case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"$INTERFACE\"\n", str); break;
158                 case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"$INTERFACE\"\n", str); break;
159         }
160 #endif
161 }