1 |
|
|
/* $OpenBSD: npppd_iface.c,v 1.13 2015/12/05 16:10:31 yasuoka Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 2009 Internet Initiative Japan Inc. |
5 |
|
|
* All rights reserved. |
6 |
|
|
* |
7 |
|
|
* Redistribution and use in source and binary forms, with or without |
8 |
|
|
* modification, are permitted provided that the following conditions |
9 |
|
|
* are met: |
10 |
|
|
* 1. Redistributions of source code must retain the above copyright |
11 |
|
|
* notice, this list of conditions and the following disclaimer. |
12 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
13 |
|
|
* notice, this list of conditions and the following disclaimer in the |
14 |
|
|
* documentation and/or other materials provided with the distribution. |
15 |
|
|
* |
16 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 |
|
|
* SUCH DAMAGE. |
27 |
|
|
*/ |
28 |
|
|
/* $Id: npppd_iface.c,v 1.13 2015/12/05 16:10:31 yasuoka Exp $ */ |
29 |
|
|
/**@file |
30 |
|
|
* The interface of npppd and kernel. |
31 |
|
|
* This is an implementation to use tun(4) or pppx(4). |
32 |
|
|
*/ |
33 |
|
|
#include <sys/types.h> |
34 |
|
|
#include <sys/ioctl.h> |
35 |
|
|
#include <sys/socket.h> |
36 |
|
|
#include <sys/uio.h> |
37 |
|
|
#include <sys/sockio.h> |
38 |
|
|
#include <netinet/in.h> |
39 |
|
|
#include <netinet/ip.h> |
40 |
|
|
#include <arpa/inet.h> |
41 |
|
|
#include <net/if_dl.h> |
42 |
|
|
#include <net/if_tun.h> |
43 |
|
|
#include <net/if_types.h> |
44 |
|
|
#include <net/if.h> |
45 |
|
|
#include <net/pipex.h> |
46 |
|
|
|
47 |
|
|
#include <fcntl.h> |
48 |
|
|
|
49 |
|
|
#include <syslog.h> |
50 |
|
|
#include <stdio.h> |
51 |
|
|
#include <stdlib.h> |
52 |
|
|
#include <string.h> |
53 |
|
|
#include <unistd.h> |
54 |
|
|
#include <errno.h> |
55 |
|
|
#include <stdarg.h> |
56 |
|
|
|
57 |
|
|
#include <time.h> |
58 |
|
|
#include <event.h> |
59 |
|
|
#include "radish.h" |
60 |
|
|
|
61 |
|
|
#include "npppd_defs.h" |
62 |
|
|
#include "npppd_local.h" |
63 |
|
|
#include "npppd_subr.h" |
64 |
|
|
#include "debugutil.h" |
65 |
|
|
#include "npppd_iface.h" |
66 |
|
|
|
67 |
|
|
#ifdef USE_NPPPD_PIPEX |
68 |
|
|
#include <net/if.h> |
69 |
|
|
#if defined(__NetBSD__) |
70 |
|
|
#include <net/if_ether.h> |
71 |
|
|
#else |
72 |
|
|
#include <netinet/if_ether.h> |
73 |
|
|
#endif |
74 |
|
|
#include <net/pipex.h> |
75 |
|
|
#endif /* USE_NPPPD_PIPEX */ |
76 |
|
|
|
77 |
|
|
#ifdef NPPPD_IFACE_DEBUG |
78 |
|
|
#define NPPPD_IFACE_DBG(x) npppd_iface_log x |
79 |
|
|
#define NPPPD_IFACE_ASSERT(cond) \ |
80 |
|
|
if (!(cond)) { \ |
81 |
|
|
fprintf(stderr, \ |
82 |
|
|
"\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\ |
83 |
|
|
, __func__, __FILE__, __LINE__); \ |
84 |
|
|
abort(); \ |
85 |
|
|
} |
86 |
|
|
#else |
87 |
|
|
#define NPPPD_IFACE_ASSERT(cond) |
88 |
|
|
#define NPPPD_IFACE_DBG(x) |
89 |
|
|
#endif |
90 |
|
|
|
91 |
|
|
static void npppd_iface_network_input_ipv4(npppd_iface *, struct pppx_hdr *, |
92 |
|
|
u_char *, int); |
93 |
|
|
static void npppd_iface_network_input(npppd_iface *, u_char *, int); |
94 |
|
|
static int npppd_iface_setup_ip(npppd_iface *); |
95 |
|
|
static void npppd_iface_io_event_handler (int, short, void *); |
96 |
|
|
static int npppd_iface_log (npppd_iface *, int, const char *, ...) |
97 |
|
|
__printflike(3,4); |
98 |
|
|
|
99 |
|
|
#ifdef USE_NPPPD_PIPEX |
100 |
|
|
static int npppd_iface_pipex_enable(npppd_iface *_this); |
101 |
|
|
static int npppd_iface_pipex_disable(npppd_iface *_this); |
102 |
|
|
#endif /* USE_NPPPD_PIPEX */ |
103 |
|
|
|
104 |
|
|
|
105 |
|
|
/** initialize npppd_iface */ |
106 |
|
|
void |
107 |
|
|
npppd_iface_init(npppd *npppd, npppd_iface *_this, struct iface *iface) |
108 |
|
|
{ |
109 |
|
|
|
110 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
111 |
|
|
memset(_this, 0, sizeof(npppd_iface)); |
112 |
|
|
|
113 |
|
|
_this->npppd = npppd; |
114 |
|
|
strlcpy(_this->ifname, iface->name, sizeof(_this->ifname)); |
115 |
|
|
_this->using_pppx = iface->is_pppx; |
116 |
|
|
_this->set_ip4addr = 1; |
117 |
|
|
_this->ip4addr = iface->ip4addr; |
118 |
|
|
_this->ipcpconf = iface->ipcpconf; |
119 |
|
|
_this->devf = -1; |
120 |
|
|
_this->initialized = 1; |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
static int |
124 |
|
|
npppd_iface_setup_ip(npppd_iface *_this) |
125 |
|
|
{ |
126 |
|
|
int sock, if_flags, changed; |
127 |
|
|
struct in_addr gw, assigned; |
128 |
|
|
struct sockaddr_in *sin0; |
129 |
|
|
struct ifreq ifr; |
130 |
|
|
struct ifaliasreq ifra; |
131 |
|
|
npppd_ppp *ppp; |
132 |
|
|
|
133 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
134 |
|
|
|
135 |
|
|
sock = -1; |
136 |
|
|
changed = 0; |
137 |
|
|
memset(&ifr, 0, sizeof(ifr)); |
138 |
|
|
|
139 |
|
|
/* get address which was assigned to interface */ |
140 |
|
|
assigned.s_addr = INADDR_NONE; |
141 |
|
|
memset(&ifr, 0, sizeof(ifr)); |
142 |
|
|
memset(&ifra, 0, sizeof(ifra)); |
143 |
|
|
strlcpy(ifr.ifr_name, _this->ifname, sizeof(ifr.ifr_name)); |
144 |
|
|
strlcpy(ifra.ifra_name, _this->ifname, sizeof(ifra.ifra_name)); |
145 |
|
|
sin0 = (struct sockaddr_in *)&ifr.ifr_addr; |
146 |
|
|
|
147 |
|
|
if (priv_get_if_addr(_this->ifname, &assigned) != 0) { |
148 |
|
|
if (errno != EADDRNOTAVAIL) { |
149 |
|
|
npppd_iface_log(_this, LOG_ERR, |
150 |
|
|
"get ip address failed: %m"); |
151 |
|
|
goto fail; |
152 |
|
|
} |
153 |
|
|
assigned.s_addr = 0; |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
if (assigned.s_addr != _this->ip4addr.s_addr) |
157 |
|
|
changed = 1; |
158 |
|
|
|
159 |
|
|
if (priv_get_if_flags(_this->ifname, &if_flags) != 0) { |
160 |
|
|
npppd_iface_log(_this, LOG_ERR, |
161 |
|
|
"ioctl(,SIOCGIFFLAGS) failed: %m"); |
162 |
|
|
goto fail; |
163 |
|
|
} |
164 |
|
|
if_flags = ifr.ifr_flags; |
165 |
|
|
if (_this->set_ip4addr != 0 && changed) { |
166 |
|
|
do { |
167 |
|
|
struct in_addr dummy; |
168 |
|
|
if (priv_delete_if_addr(_this->ifname) != 0) { |
169 |
|
|
if (errno == EADDRNOTAVAIL) |
170 |
|
|
break; |
171 |
|
|
npppd_iface_log(_this, LOG_ERR, |
172 |
|
|
"delete ipaddress %s failed: %m", |
173 |
|
|
_this->ifname); |
174 |
|
|
goto fail; |
175 |
|
|
} |
176 |
|
|
if (priv_get_if_addr(_this->ifname, &dummy) != 0) { |
177 |
|
|
if (errno == EADDRNOTAVAIL) |
178 |
|
|
break; |
179 |
|
|
npppd_iface_log(_this, LOG_ERR, |
180 |
|
|
"cannot get ipaddress %s failed: %m", |
181 |
|
|
_this->ifname); |
182 |
|
|
goto fail; |
183 |
|
|
} |
184 |
|
|
} while (1); |
185 |
|
|
|
186 |
|
|
/* ifconfig tun1 down */ |
187 |
|
|
if (priv_set_if_flags(_this->ifname, |
188 |
|
|
if_flags & ~(IFF_UP | IFF_BROADCAST)) != 0) { |
189 |
|
|
npppd_iface_log(_this, LOG_ERR, |
190 |
|
|
"disabling %s failed: %m", _this->ifname); |
191 |
|
|
goto fail; |
192 |
|
|
} |
193 |
|
|
if (priv_set_if_addr(_this->ifname, &_this->ip4addr) != 0 && |
194 |
|
|
errno != EEXIST) { |
195 |
|
|
npppd_iface_log(_this, LOG_ERR, |
196 |
|
|
"Cannot assign tun device ip address: %m"); |
197 |
|
|
goto fail; |
198 |
|
|
} |
199 |
|
|
/* erase old route */ |
200 |
|
|
if (assigned.s_addr != 0) { |
201 |
|
|
gw.s_addr = htonl(INADDR_LOOPBACK); |
202 |
|
|
in_host_route_delete(&assigned, &gw); |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
assigned.s_addr = _this->ip4addr.s_addr; |
206 |
|
|
|
207 |
|
|
} |
208 |
|
|
_this->ip4addr.s_addr = assigned.s_addr; |
209 |
|
|
if (npppd_iface_ip_is_ready(_this)) { |
210 |
|
|
if (changed) { |
211 |
|
|
/* |
212 |
|
|
* If there is a PPP session which was assigned |
213 |
|
|
* interface IP address, disconnect it. |
214 |
|
|
*/ |
215 |
|
|
ppp = npppd_get_ppp_by_ip(_this->npppd, _this->ip4addr); |
216 |
|
|
if (ppp != NULL) { |
217 |
|
|
npppd_iface_log(_this, LOG_ERR, |
218 |
|
|
"Assigning %s, but ppp=%d is using " |
219 |
|
|
"the address. Requested the ppp to stop", |
220 |
|
|
inet_ntoa(_this->ip4addr), ppp->id); |
221 |
|
|
ppp_stop(ppp, "Administrative reason"); |
222 |
|
|
} |
223 |
|
|
} |
224 |
|
|
/* ifconfig tun1 up */ |
225 |
|
|
if (priv_set_if_flags(_this->ifname, |
226 |
|
|
if_flags | IFF_UP | IFF_MULTICAST) != 0) { |
227 |
|
|
npppd_iface_log(_this, LOG_ERR, |
228 |
|
|
"enabling %s failed: %m", _this->ifname); |
229 |
|
|
goto fail; |
230 |
|
|
} |
231 |
|
|
/* |
232 |
|
|
* Add routing entry to communicate from host itself to |
233 |
|
|
* _this->ip4addr. |
234 |
|
|
*/ |
235 |
|
|
gw.s_addr = htonl(INADDR_LOOPBACK); |
236 |
|
|
in_host_route_add(&_this->ip4addr, &gw, LOOPBACK_IFNAME, 0); |
237 |
|
|
} |
238 |
|
|
close(sock); sock = -1; |
239 |
|
|
|
240 |
|
|
return 0; |
241 |
|
|
fail: |
242 |
|
|
if (sock >= 0) |
243 |
|
|
close(sock); |
244 |
|
|
|
245 |
|
|
return 1; |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
/** set tunnel end address */ |
249 |
|
|
int |
250 |
|
|
npppd_iface_reinit(npppd_iface *_this, struct iface *iface) |
251 |
|
|
{ |
252 |
|
|
int rval; |
253 |
|
|
struct in_addr backup; |
254 |
|
|
char buf0[128], buf1[128]; |
255 |
|
|
|
256 |
|
|
_this->ipcpconf = iface->ipcpconf; |
257 |
|
|
backup = _this->ip4addr; |
258 |
|
|
_this->ip4addr = iface->ip4addr; |
259 |
|
|
|
260 |
|
|
if (_this->using_pppx) |
261 |
|
|
return 0; |
262 |
|
|
if ((rval = npppd_iface_setup_ip(_this)) != 0) |
263 |
|
|
return rval; |
264 |
|
|
|
265 |
|
|
if (backup.s_addr != _this->ip4addr.s_addr) { |
266 |
|
|
npppd_iface_log(_this, LOG_INFO, "Reinited ip4addr %s=>%s", |
267 |
|
|
(backup.s_addr != INADDR_ANY) |
268 |
|
|
? inet_ntop(AF_INET, &backup, buf0, sizeof(buf0)) |
269 |
|
|
: "(not assigned)", |
270 |
|
|
(_this->ip4addr.s_addr != INADDR_ANY) |
271 |
|
|
? inet_ntop(AF_INET, &_this->ip4addr, buf1, |
272 |
|
|
sizeof(buf1)) |
273 |
|
|
: "(not assigned)"); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
return 0; |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
/** start npppd_iface */ |
280 |
|
|
int |
281 |
|
|
npppd_iface_start(npppd_iface *_this) |
282 |
|
|
{ |
283 |
|
|
int x; |
284 |
|
|
char buf[PATH_MAX]; |
285 |
|
|
|
286 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
287 |
|
|
|
288 |
|
|
/* open device file */ |
289 |
|
|
snprintf(buf, sizeof(buf), "/dev/%s", _this->ifname); |
290 |
|
|
if ((_this->devf = priv_open(buf, O_RDWR | O_NONBLOCK)) < 0) { |
291 |
|
|
npppd_iface_log(_this, LOG_ERR, "open(%s) failed: %m", buf); |
292 |
|
|
goto fail; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
if (_this->using_pppx == 0) { |
296 |
|
|
x = IFF_BROADCAST; |
297 |
|
|
if (ioctl(_this->devf, TUNSIFMODE, &x) != 0) { |
298 |
|
|
npppd_iface_log(_this, LOG_ERR, |
299 |
|
|
"ioctl(TUNSIFMODE=IFF_BROADCAST) failed " |
300 |
|
|
"in %s(): %m", __func__); |
301 |
|
|
goto fail; |
302 |
|
|
} |
303 |
|
|
} |
304 |
|
|
|
305 |
|
|
event_set(&_this->ev, _this->devf, EV_READ | EV_PERSIST, |
306 |
|
|
npppd_iface_io_event_handler, _this); |
307 |
|
|
event_add(&_this->ev, NULL); |
308 |
|
|
|
309 |
|
|
if (_this->using_pppx == 0) { |
310 |
|
|
if (npppd_iface_setup_ip(_this) != 0) |
311 |
|
|
goto fail; |
312 |
|
|
} |
313 |
|
|
|
314 |
|
|
#ifdef USE_NPPPD_PIPEX |
315 |
|
|
if (npppd_iface_pipex_enable(_this) != 0) { |
316 |
|
|
log_printf(LOG_WARNING, |
317 |
|
|
"npppd_iface_pipex_enable() failed: %m"); |
318 |
|
|
} |
319 |
|
|
#else |
320 |
|
|
if (_this->using_pppx) { |
321 |
|
|
npppd_iface_log(_this, LOG_ERR, |
322 |
|
|
"pipex is required when using pppx interface"); |
323 |
|
|
goto fail; |
324 |
|
|
} |
325 |
|
|
#endif /* USE_NPPPD_PIPEX */ |
326 |
|
|
|
327 |
|
|
if (_this->using_pppx) { |
328 |
|
|
npppd_iface_log(_this, LOG_INFO, "Started pppx"); |
329 |
|
|
} else { |
330 |
|
|
npppd_iface_log(_this, LOG_INFO, "Started ip4addr=%s", |
331 |
|
|
(npppd_iface_ip_is_ready(_this))? |
332 |
|
|
inet_ntop(AF_INET, &_this->ip4addr, buf, |
333 |
|
|
sizeof(buf)) : "(not assigned)"); |
334 |
|
|
} |
335 |
|
|
_this->started = 1; |
336 |
|
|
|
337 |
|
|
return 0; |
338 |
|
|
fail: |
339 |
|
|
if (_this->devf >= 0) { |
340 |
|
|
event_del(&_this->ev); |
341 |
|
|
close(_this->devf); |
342 |
|
|
} |
343 |
|
|
_this->devf = -1; |
344 |
|
|
|
345 |
|
|
return -1; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
/** stop to use npppd_iface */ |
349 |
|
|
void |
350 |
|
|
npppd_iface_stop(npppd_iface *_this) |
351 |
|
|
{ |
352 |
|
|
struct in_addr gw; |
353 |
|
|
|
354 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
355 |
|
|
if (_this->using_pppx == 0) { |
356 |
|
|
priv_delete_if_addr(_this->ifname); |
357 |
|
|
gw.s_addr = htonl(INADDR_LOOPBACK); |
358 |
|
|
in_host_route_delete(&_this->ip4addr, &gw); |
359 |
|
|
} |
360 |
|
|
if (_this->devf >= 0) { |
361 |
|
|
#ifdef USE_NPPPD_PIPEX |
362 |
|
|
if (npppd_iface_pipex_disable(_this) != 0) { |
363 |
|
|
log_printf(LOG_CRIT, |
364 |
|
|
"npppd_iface_pipex_disable() failed: %m"); |
365 |
|
|
} |
366 |
|
|
#endif /* USE_NPPPD_PIPEX */ |
367 |
|
|
|
368 |
|
|
event_del(&_this->ev); |
369 |
|
|
close(_this->devf); |
370 |
|
|
npppd_iface_log(_this, LOG_INFO, "Stopped"); |
371 |
|
|
} |
372 |
|
|
_this->devf = -1; |
373 |
|
|
_this->started = 0; |
374 |
|
|
event_del(&_this->ev); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
/** finalize npppd_iface */ |
378 |
|
|
void |
379 |
|
|
npppd_iface_fini(npppd_iface *_this) |
380 |
|
|
{ |
381 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
382 |
|
|
_this->initialized = 0; |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
|
386 |
|
|
/*********************************************************************** |
387 |
|
|
* PIPEX related functions |
388 |
|
|
***********************************************************************/ |
389 |
|
|
#ifdef USE_NPPPD_PIPEX |
390 |
|
|
|
391 |
|
|
/** enable PIPEX on PPPAC interface */ |
392 |
|
|
int |
393 |
|
|
npppd_iface_pipex_enable(npppd_iface *_this) |
394 |
|
|
{ |
395 |
|
|
int enable = 1; |
396 |
|
|
|
397 |
|
|
return ioctl(_this->devf, PIPEXSMODE, &enable); |
398 |
|
|
} |
399 |
|
|
|
400 |
|
|
/** disable PIPEX on PPPAC interface */ |
401 |
|
|
int |
402 |
|
|
npppd_iface_pipex_disable(npppd_iface *_this) |
403 |
|
|
{ |
404 |
|
|
int disable = 0; |
405 |
|
|
|
406 |
|
|
return ioctl(_this->devf, PIPEXSMODE, &disable); |
407 |
|
|
} |
408 |
|
|
|
409 |
|
|
#endif /* USE_NPPPD_PIPEX */ |
410 |
|
|
|
411 |
|
|
|
412 |
|
|
/*********************************************************************** |
413 |
|
|
* I/O related functions |
414 |
|
|
***********************************************************************/ |
415 |
|
|
/** I/O event handler */ |
416 |
|
|
static void |
417 |
|
|
npppd_iface_io_event_handler(int fd, short evtype, void *data) |
418 |
|
|
{ |
419 |
|
|
int sz; |
420 |
|
|
u_char buffer[8192]; |
421 |
|
|
npppd_iface *_this; |
422 |
|
|
|
423 |
|
|
NPPPD_IFACE_ASSERT((evtype & EV_READ) != 0); |
424 |
|
|
|
425 |
|
|
_this = data; |
426 |
|
|
NPPPD_IFACE_ASSERT(_this->devf >= 0); |
427 |
|
|
do { |
428 |
|
|
sz = read(_this->devf, buffer, sizeof(buffer)); |
429 |
|
|
if (sz <= 0) { |
430 |
|
|
if (sz == 0) |
431 |
|
|
npppd_iface_log(_this, LOG_ERR, |
432 |
|
|
"file is closed"); |
433 |
|
|
else if (errno == EAGAIN) |
434 |
|
|
break; |
435 |
|
|
else |
436 |
|
|
npppd_iface_log(_this, LOG_ERR, |
437 |
|
|
"read failed: %m"); |
438 |
|
|
npppd_iface_stop(_this); |
439 |
|
|
return; |
440 |
|
|
} |
441 |
|
|
npppd_iface_network_input(_this, buffer, sz); |
442 |
|
|
|
443 |
|
|
} while (1 /* CONSTCOND */); |
444 |
|
|
|
445 |
|
|
return; |
446 |
|
|
} |
447 |
|
|
|
448 |
|
|
/** structure of argument of npppd_iface_network_input_delegate */ |
449 |
|
|
struct npppd_iface_network_input_arg{ |
450 |
|
|
npppd_iface *_this; |
451 |
|
|
u_char *pktp; |
452 |
|
|
int lpktp; |
453 |
|
|
}; |
454 |
|
|
|
455 |
|
|
/** callback function which works for each PPP session */ |
456 |
|
|
static int |
457 |
|
|
npppd_iface_network_input_delegate(struct radish *radish, void *args0) |
458 |
|
|
{ |
459 |
|
|
npppd_ppp *ppp; |
460 |
|
|
struct sockaddr_npppd *snp; |
461 |
|
|
struct npppd_iface_network_input_arg *args; |
462 |
|
|
|
463 |
|
|
snp = radish->rd_rtent; |
464 |
|
|
|
465 |
|
|
if (snp->snp_type == SNP_PPP) { |
466 |
|
|
args = args0; |
467 |
|
|
ppp = snp->snp_data_ptr; |
468 |
|
|
if (ppp_iface(ppp) != args->_this) |
469 |
|
|
return 0; |
470 |
|
|
#ifdef USE_NPPPD_MPPE |
471 |
|
|
if (MPPE_SEND_READY(ppp)) { |
472 |
|
|
/* output via MPPE if MPPE started */ |
473 |
|
|
mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, args->pktp, |
474 |
|
|
args->lpktp); |
475 |
|
|
} else if (MPPE_IS_REQUIRED(ppp)) { |
476 |
|
|
/* in case MPPE not started but MPPE is mandatory, */ |
477 |
|
|
/* it is not necessary to log because of multicast. */ |
478 |
|
|
return 0; |
479 |
|
|
} |
480 |
|
|
#endif |
481 |
|
|
ppp_output(ppp, PPP_PROTO_IP, 0, 0, args->pktp, args->lpktp); |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
return 0; |
485 |
|
|
} |
486 |
|
|
|
487 |
|
|
static void |
488 |
|
|
npppd_iface_network_input_ipv4(npppd_iface *_this, struct pppx_hdr *pppx, |
489 |
|
|
u_char *pktp, int lpktp) |
490 |
|
|
{ |
491 |
|
|
struct ip *iphdr; |
492 |
|
|
npppd *_npppd; |
493 |
|
|
npppd_ppp *ppp; |
494 |
|
|
struct npppd_iface_network_input_arg input_arg; |
495 |
|
|
|
496 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
497 |
|
|
NPPPD_IFACE_ASSERT(pktp != NULL); |
498 |
|
|
|
499 |
|
|
iphdr = (struct ip *)pktp; |
500 |
|
|
_npppd = _this->npppd; |
501 |
|
|
|
502 |
|
|
if (lpktp < sizeof(iphdr)) { |
503 |
|
|
npppd_iface_log(_this, LOG_ERR, "Received short packet."); |
504 |
|
|
return; |
505 |
|
|
} |
506 |
|
|
if (_this->using_pppx) |
507 |
|
|
ppp = npppd_get_ppp_by_id(_npppd, pppx->pppx_id); |
508 |
|
|
else { |
509 |
|
|
if (IN_MULTICAST(ntohl(iphdr->ip_dst.s_addr))) { |
510 |
|
|
NPPPD_IFACE_ASSERT( |
511 |
|
|
((npppd *)(_this->npppd))->rd != NULL); |
512 |
|
|
input_arg._this = _this; |
513 |
|
|
input_arg.pktp = pktp; |
514 |
|
|
input_arg.lpktp = lpktp; |
515 |
|
|
/* delegate */ |
516 |
|
|
rd_walktree(((npppd *)(_this->npppd))->rd, |
517 |
|
|
npppd_iface_network_input_delegate, &input_arg); |
518 |
|
|
return; |
519 |
|
|
} |
520 |
|
|
ppp = npppd_get_ppp_by_ip(_npppd, iphdr->ip_dst); |
521 |
|
|
} |
522 |
|
|
|
523 |
|
|
if (ppp == NULL) { |
524 |
|
|
#ifdef NPPPD_DEBUG |
525 |
|
|
log_printf(LOG_INFO, "%s received a packet to unknown " |
526 |
|
|
"%s.", _this->ifname, inet_ntoa(iphdr->ip_dst)); |
527 |
|
|
#endif |
528 |
|
|
return; |
529 |
|
|
} |
530 |
|
|
#ifndef NO_ADJUST_MSS |
531 |
|
|
if (ppp->adjust_mss) { |
532 |
|
|
adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru)); |
533 |
|
|
} |
534 |
|
|
#endif |
535 |
|
|
if (ppp->timeout_sec > 0 && !ip_is_idle_packet(iphdr, lpktp)) |
536 |
|
|
ppp_reset_idle_timeout(ppp); |
537 |
|
|
|
538 |
|
|
#ifdef USE_NPPPD_MPPE |
539 |
|
|
if (MPPE_SEND_READY(ppp)) { |
540 |
|
|
/* output via MPPE if MPPE started */ |
541 |
|
|
mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, pktp, lpktp); |
542 |
|
|
return; |
543 |
|
|
} else if (MPPE_IS_REQUIRED(ppp)) { |
544 |
|
|
/* in case MPPE not started but MPPE is mandatory */ |
545 |
|
|
ppp_log(ppp, LOG_WARNING, "A packet received from network, " |
546 |
|
|
"but MPPE is not started."); |
547 |
|
|
return; |
548 |
|
|
} |
549 |
|
|
#endif |
550 |
|
|
ppp_output(ppp, PPP_PROTO_IP, 0, 0, pktp, lpktp); |
551 |
|
|
} |
552 |
|
|
|
553 |
|
|
/** |
554 |
|
|
* This function is called when an input packet come from network(tun). |
555 |
|
|
* Currently, it assumes that it input IPv4 packet. |
556 |
|
|
*/ |
557 |
|
|
static void |
558 |
|
|
npppd_iface_network_input(npppd_iface *_this, u_char *pktp, int lpktp) |
559 |
|
|
{ |
560 |
|
|
uint32_t af; |
561 |
|
|
struct pppx_hdr *pppx = NULL; |
562 |
|
|
|
563 |
|
|
if (_this->using_pppx) { |
564 |
|
|
if (lpktp < sizeof(struct pppx_hdr)) { |
565 |
|
|
npppd_iface_log(_this, LOG_ERR, |
566 |
|
|
"Received short packet."); |
567 |
|
|
return; |
568 |
|
|
} |
569 |
|
|
pppx = (struct pppx_hdr *)pktp; |
570 |
|
|
pktp += sizeof(struct pppx_hdr); |
571 |
|
|
lpktp -= sizeof(struct pppx_hdr); |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
if (lpktp < sizeof(uint32_t)) { |
575 |
|
|
npppd_iface_log(_this, LOG_ERR, "Received short packet."); |
576 |
|
|
return; |
577 |
|
|
} |
578 |
|
|
GETLONG(af, pktp); |
579 |
|
|
lpktp -= sizeof(uint32_t); |
580 |
|
|
|
581 |
|
|
switch (af) { |
582 |
|
|
case AF_INET: |
583 |
|
|
npppd_iface_network_input_ipv4(_this, pppx, pktp, lpktp); |
584 |
|
|
break; |
585 |
|
|
|
586 |
|
|
default: |
587 |
|
|
NPPPD_IFACE_ASSERT(0); |
588 |
|
|
break; |
589 |
|
|
|
590 |
|
|
} |
591 |
|
|
} |
592 |
|
|
|
593 |
|
|
/** write to tunnel device */ |
594 |
|
|
void |
595 |
|
|
npppd_iface_write(npppd_iface *_this, npppd_ppp *ppp, int proto, u_char *pktp, |
596 |
|
|
int lpktp) |
597 |
|
|
{ |
598 |
|
|
int niov = 0, tlen; |
599 |
|
|
uint32_t th; |
600 |
|
|
struct iovec iov[3]; |
601 |
|
|
struct pppx_hdr pppx; |
602 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
603 |
|
|
NPPPD_IFACE_ASSERT(_this->devf >= 0); |
604 |
|
|
|
605 |
|
|
tlen = 0; |
606 |
|
|
th = htonl(proto); |
607 |
|
|
if (_this->using_pppx) { |
608 |
|
|
pppx.pppx_proto = npppd_pipex_proto(ppp->tunnel_type); |
609 |
|
|
pppx.pppx_id = ppp->tunnel_session_id; |
610 |
|
|
iov[niov].iov_base = &pppx; |
611 |
|
|
iov[niov++].iov_len = sizeof(pppx); |
612 |
|
|
tlen += sizeof(pppx); |
613 |
|
|
} |
614 |
|
|
iov[niov].iov_base = &th; |
615 |
|
|
iov[niov++].iov_len = sizeof(th); |
616 |
|
|
tlen += sizeof(th); |
617 |
|
|
iov[niov].iov_base = pktp; |
618 |
|
|
iov[niov++].iov_len = lpktp; |
619 |
|
|
tlen += lpktp; |
620 |
|
|
|
621 |
|
|
if (writev(_this->devf, iov, niov) != tlen) |
622 |
|
|
npppd_iface_log(_this, LOG_ERR, "write failed: %m"); |
623 |
|
|
} |
624 |
|
|
|
625 |
|
|
/*********************************************************************** |
626 |
|
|
* misc functions |
627 |
|
|
***********************************************************************/ |
628 |
|
|
/** Log it which starts the label based on this instance. */ |
629 |
|
|
static int |
630 |
|
|
npppd_iface_log(npppd_iface *_this, int prio, const char *fmt, ...) |
631 |
|
|
{ |
632 |
|
|
int status; |
633 |
|
|
char logbuf[BUFSIZ]; |
634 |
|
|
va_list ap; |
635 |
|
|
|
636 |
|
|
NPPPD_IFACE_ASSERT(_this != NULL); |
637 |
|
|
|
638 |
|
|
va_start(ap, fmt); |
639 |
|
|
snprintf(logbuf, sizeof(logbuf), "%s %s", _this->ifname, fmt); |
640 |
|
|
status = vlog_printf(prio, logbuf, ap); |
641 |
|
|
va_end(ap); |
642 |
|
|
|
643 |
|
|
return status; |
644 |
|
|
} |