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