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         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         (void)out;
75         fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
76 }
77
78 void ifconfig_slaac(FILE *out) {
79         (void)out;
80         // It's the default?
81 }
82
83 bool ifconfig_footer(FILE *out) {
84         return ftell(out) != start;
85 }
86 #endif
87
88 static subnet_t ipv4, ipv6;
89
90 void ifconfig_address(FILE *out, const char *value) {
91         subnet_t address = {0};
92         char address_str[MAXNETSTR];
93
94         if(!str2net(&address, value) || !net2str(address_str, sizeof(address_str), &address)) {
95                 fprintf(stderr, "Could not parse address in Ifconfig statement\n");
96                 return;
97         }
98
99         switch(address.type) {
100         case SUBNET_IPV4:
101                 ipv4 = address;
102                 break;
103
104         case SUBNET_IPV6:
105                 ipv6 = address;
106                 break;
107
108         case SUBNET_MAC:
109         default:
110                 return;
111         }
112
113 #if defined(HAVE_LINUX)
114
115         switch(address.type) {
116         case SUBNET_MAC:
117                 fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str);
118                 break;
119
120         case SUBNET_IPV4:
121                 fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str);
122                 break;
123
124         case SUBNET_IPV6:
125                 fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str);
126                 break;
127
128         default:
129                 return;
130         }
131
132 #elif defined(HAVE_WINDOWS)
133
134         switch(address.type) {
135         case SUBNET_MAC:
136                 fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str);
137                 break;
138
139         case SUBNET_IPV4:
140                 fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" static %s\n", address_str);
141                 break;
142
143         case SUBNET_IPV6:
144                 fprintf(out, "netsh interface ipv6 set address \"%%INTERFACE%%\" %s\n", address_str);
145                 break;
146
147         default:
148                 return;
149         }
150
151 #else // assume BSD
152
153         switch(address.type) {
154         case SUBNET_MAC:
155                 fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str);
156                 break;
157
158         case SUBNET_IPV4:
159                 fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str);
160                 break;
161
162         case SUBNET_IPV6:
163                 fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str);
164                 break;
165
166         default:
167                 return;
168         }
169
170 #endif
171 }
172
173 void ifconfig_route(FILE *out, const char *value) {
174         subnet_t subnet = {0}, gateway = {0};
175         char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = "";
176         char *sep = strchr(value, ' ');
177
178         if(sep) {
179                 *sep++ = 0;
180         }
181
182         if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof(subnet_str), &subnet) || subnet.type == SUBNET_MAC) {
183                 fprintf(stderr, "Could not parse subnet in Route statement\n");
184                 return;
185         }
186
187         if(sep) {
188                 if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof(gateway_str), &gateway) || gateway.type != subnet.type) {
189                         fprintf(stderr, "Could not parse gateway in Route statement\n");
190                         return;
191                 }
192
193                 char *slash = strchr(gateway_str, '/');
194
195                 if(slash) {
196                         *slash = 0;
197                 }
198         }
199
200 #if defined(HAVE_LINUX)
201
202         if(*gateway_str) {
203                 switch(subnet.type) {
204                 case SUBNET_IPV4:
205                         fprintf(out, "ip route add %s via %s dev \"$INTERFACE\" onlink\n", subnet_str, gateway_str);
206                         break;
207
208                 case SUBNET_IPV6:
209                         fprintf(out, "ip route add %s via %s dev \"$INTERFACE\" onlink\n", subnet_str, gateway_str);
210                         break;
211
212                 case SUBNET_MAC:
213                 default:
214                         return;
215                 }
216         } else {
217                 switch(subnet.type) {
218                 case SUBNET_IPV4:
219                         fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str);
220                         break;
221
222                 case SUBNET_IPV6:
223                         fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str);
224                         break;
225
226                 case SUBNET_MAC:
227                 default:
228                         return;
229                 }
230         }
231
232 #elif defined(HAVE_WINDOWS)
233
234         if(*gateway_str) {
235                 switch(subnet.type) {
236                 case SUBNET_IPV4:
237                         fprintf(out, "netsh interface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str);
238                         break;
239
240                 case SUBNET_IPV6:
241                         fprintf(out, "netsh interface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str);
242                         break;
243
244                 case SUBNET_MAC:
245                 default:
246                         return;
247                 }
248         } else {
249                 switch(subnet.type) {
250                 case SUBNET_IPV4:
251                         fprintf(out, "netsh interface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str);
252                         break;
253
254                 case SUBNET_IPV6:
255                         fprintf(out, "netsh interface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str);
256                         break;
257
258                 case SUBNET_MAC:
259                 default:
260                         return;
261                 }
262         }
263
264 #else // assume BSD
265
266         if(!*gateway_str) {
267                 switch(subnet.type) {
268                 case SUBNET_IPV4:
269                         if(!ipv4.type) {
270                                 fprintf(stderr, "Route requested but no Ifconfig\n");
271                                 return;
272                         }
273
274                         net2str(gateway_str, sizeof(gateway_str), &ipv4);
275                         break;
276
277                 case SUBNET_IPV6:
278                         if(!ipv6.type) {
279                                 fprintf(stderr, "Route requested but no Ifconfig\n");
280                                 return;
281                         }
282
283                         net2str(gateway_str, sizeof(gateway_str), &ipv6);
284                         break;
285
286                 case SUBNET_MAC:
287                 default:
288                         return;
289                 }
290
291                 char *slash = strchr(gateway_str, '/');
292
293                 if(slash) {
294                         *slash = 0;
295                 }
296         }
297
298         switch(subnet.type) {
299         case SUBNET_IPV4:
300                 fprintf(out, "route add %s %s\n", subnet_str, gateway_str);
301                 break;
302
303         case SUBNET_IPV6:
304                 fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str);
305                 break;
306
307         case SUBNET_MAC:
308         default:
309                 return;
310         }
311
312 #endif
313 }