GitHub CI: update list of container images
[tinc] / src / ifconfig.c
1 /*
2     ifconfig.c -- Generate platform specific interface configuration commands
3     Copyright (C) 2016-2018 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_WINDOWS
29 void ifconfig_header(FILE *out) {
30         fprintf(out, "#!/bin/sh\n");
31 #ifdef HAVE_LINUX
32         fprintf(out, "ip link set \"$INTERFACE\" up\n");
33 #endif
34         start = ftell(out);
35 }
36
37 void ifconfig_dhcp(FILE *out) {
38         fprintf(out, "dhclient -nw \"$INTERFACE\"\n");
39 }
40
41 void ifconfig_dhcp6(FILE *out) {
42         fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n");
43 }
44
45 void ifconfig_slaac(FILE *out) {
46 #ifdef HAVE_LINUX
47         fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n");
48         fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n");
49 #else
50         fprintf(out, "rtsol \"$INTERFACE\" &\n");
51 #endif
52 }
53
54 bool ifconfig_footer(FILE *out) {
55         if(ftell(out) == start) {
56                 fprintf(out,
57 #ifdef HAVE_LINUX
58                         "#ip addr add <your vpn IP address>/<prefix of whole VPN> dev $INTERFACE\n"
59 #else
60                         "#ifconfig $INTERFACE <your vpn IP address>/<prefix of whole VPN>\n"
61 #endif
62                         "\n"
63                         "echo \"Unconfigured tinc-up script, please edit '$0'!\" >&2\n");
64                 return false;
65         } else {
66 #ifndef HAVE_LINUX
67                 fprintf(out, "ifconfig \"$INTERFACE\" up\n");
68 #endif
69                 return true;
70         }
71 }
72 #else
73 void ifconfig_header(FILE *out) {
74         start = ftell(out);
75 }
76
77 void ifconfig_dhcp(FILE *out) {
78         fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" dhcp\n");
79 }
80
81 void ifconfig_dhcp6(FILE *out) {
82         (void)out;
83         fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
84 }
85
86 void ifconfig_slaac(FILE *out) {
87         (void)out;
88         // It's the default?
89 }
90
91 bool ifconfig_footer(FILE *out) {
92         return ftell(out) != start;
93 }
94 #endif
95
96 static subnet_t ipv4, ipv6;
97
98 void ifconfig_address(FILE *out, const char *value) {
99         subnet_t address = {0};
100         char address_str[MAXNETSTR];
101
102         if(!str2net(&address, value) || !net2str(address_str, sizeof(address_str), &address)) {
103                 fprintf(stderr, "Could not parse address in Ifconfig statement\n");
104                 return;
105         }
106
107         switch(address.type) {
108         case SUBNET_IPV4:
109                 ipv4 = address;
110                 break;
111
112         case SUBNET_IPV6:
113                 ipv6 = address;
114                 break;
115
116         case SUBNET_MAC:
117         default:
118                 return;
119         }
120
121 #if defined(HAVE_LINUX)
122
123         switch(address.type) {
124         case SUBNET_MAC:
125                 fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str);
126                 break;
127
128         case SUBNET_IPV4:
129                 fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str);
130                 break;
131
132         case SUBNET_IPV6:
133                 fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str);
134                 break;
135
136         default:
137                 return;
138         }
139
140 #elif defined(HAVE_WINDOWS)
141
142         switch(address.type) {
143         case SUBNET_MAC:
144                 fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str);
145                 break;
146
147         case SUBNET_IPV4:
148                 fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" static %s\n", address_str);
149                 break;
150
151         case SUBNET_IPV6:
152                 fprintf(out, "netsh interface ipv6 set address \"%%INTERFACE%%\" %s\n", address_str);
153                 break;
154
155         default:
156                 return;
157         }
158
159 #else // assume BSD
160
161         switch(address.type) {
162         case SUBNET_MAC:
163                 fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str);
164                 break;
165
166         case SUBNET_IPV4:
167                 fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str);
168                 break;
169
170         case SUBNET_IPV6:
171                 fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str);
172                 break;
173
174         default:
175                 return;
176         }
177
178 #endif
179 }
180
181 void ifconfig_route(FILE *out, const char *value) {
182         subnet_t subnet = {0}, gateway = {0};
183         char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = "";
184         char *sep = strchr(value, ' ');
185
186         if(sep) {
187                 *sep++ = 0;
188         }
189
190         if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof(subnet_str), &subnet) || subnet.type == SUBNET_MAC) {
191                 fprintf(stderr, "Could not parse subnet in Route statement\n");
192                 return;
193         }
194
195         if(sep) {
196                 if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof(gateway_str), &gateway) || gateway.type != subnet.type) {
197                         fprintf(stderr, "Could not parse gateway in Route statement\n");
198                         return;
199                 }
200
201                 char *slash = strchr(gateway_str, '/');
202
203                 if(slash) {
204                         *slash = 0;
205                 }
206         }
207
208 #if defined(HAVE_LINUX)
209
210         if(*gateway_str) {
211                 switch(subnet.type) {
212                 case SUBNET_IPV4:
213                         fprintf(out, "ip route add %s via %s dev \"$INTERFACE\" onlink\n", subnet_str, gateway_str);
214                         break;
215
216                 case SUBNET_IPV6:
217                         fprintf(out, "ip route add %s via %s dev \"$INTERFACE\" onlink\n", subnet_str, gateway_str);
218                         break;
219
220                 case SUBNET_MAC:
221                 default:
222                         return;
223                 }
224         } else {
225                 switch(subnet.type) {
226                 case SUBNET_IPV4:
227                         fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str);
228                         break;
229
230                 case SUBNET_IPV6:
231                         fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str);
232                         break;
233
234                 case SUBNET_MAC:
235                 default:
236                         return;
237                 }
238         }
239
240 #elif defined(HAVE_WINDOWS)
241
242         if(*gateway_str) {
243                 switch(subnet.type) {
244                 case SUBNET_IPV4:
245                         fprintf(out, "netsh interface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str);
246                         break;
247
248                 case SUBNET_IPV6:
249                         fprintf(out, "netsh interface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str);
250                         break;
251
252                 case SUBNET_MAC:
253                 default:
254                         return;
255                 }
256         } else {
257                 switch(subnet.type) {
258                 case SUBNET_IPV4:
259                         fprintf(out, "netsh interface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str);
260                         break;
261
262                 case SUBNET_IPV6:
263                         fprintf(out, "netsh interface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str);
264                         break;
265
266                 case SUBNET_MAC:
267                 default:
268                         return;
269                 }
270         }
271
272 #else // assume BSD
273
274         if(!*gateway_str) {
275                 switch(subnet.type) {
276                 case SUBNET_IPV4:
277                         if(!ipv4.type) {
278                                 fprintf(stderr, "Route requested but no Ifconfig\n");
279                                 return;
280                         }
281
282                         net2str(gateway_str, sizeof(gateway_str), &ipv4);
283                         break;
284
285                 case SUBNET_IPV6:
286                         if(!ipv6.type) {
287                                 fprintf(stderr, "Route requested but no Ifconfig\n");
288                                 return;
289                         }
290
291                         net2str(gateway_str, sizeof(gateway_str), &ipv6);
292                         break;
293
294                 case SUBNET_MAC:
295                 default:
296                         return;
297                 }
298
299                 char *slash = strchr(gateway_str, '/');
300
301                 if(slash) {
302                         *slash = 0;
303                 }
304         }
305
306         switch(subnet.type) {
307         case SUBNET_IPV4:
308                 fprintf(out, "route add %s %s\n", subnet_str, gateway_str);
309                 break;
310
311         case SUBNET_IPV6:
312                 fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str);
313                 break;
314
315         case SUBNET_MAC:
316         default:
317                 return;
318         }
319
320 #endif
321 }