1 /* $NetBSD: pppoectl.c,v 1.20 2005/06/27 01:00:06 christos Exp $ */
4 * Copyright (c) 1997 Joerg Wunsch
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * From: spppcontrol.c,v 1.3 1998/01/07 07:55:26 charnier Exp
31 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: pppoectl.c,v 1.20 2005/06/27 01:00:06 christos Exp $");
38 #include <sys/param.h>
39 #include <sys/callout.h>
40 #include <sys/ioctl.h>
42 #include <sys/socket.h>
44 #include <sys/sysctl.h>
46 #include <net/if_sppp.h>
47 #include <net/if_pppoe.h>
55 static void usage(void);
56 static void print_error(const char *ifname
, int error
, const char * str
);
57 static void print_vals(const char *ifname
, int phase
, struct spppauthcfg
*sp
,
58 int lcp_timeout
, time_t idle_timeout
, int authfailures
,
59 int max_auth_failures
, u_int maxalive
, time_t max_noreceive
);
60 const char *phase_name(int phase
);
61 const char *proto_name(int proto
);
62 const char *authflags(int flags
);
63 static void pppoectl_argument(char *arg
);
67 int set_auth
, set_lcp
, set_idle_to
, set_auth_failure
, set_dns
,
68 clear_auth_failure_count
, set_keepalive
;
70 int max_noreceive
= -1;
71 struct spppauthcfg spr
;
72 struct sppplcpcfg lcp
;
73 struct spppstatus status
;
74 struct spppidletimeout timeout
;
75 struct spppauthfailurestats authfailstats
;
76 struct spppauthfailuresettings authfailset
;
77 struct spppdnssettings dnssettings
;
78 struct spppkeepalivesettings keepalivesettings
;
81 main(int argc
, char **argv
)
85 int errs
= 0, verbose
= 0, dump
= 0, dns1
= 0, dns2
= 0;
87 const char *eth_if_name
, *access_concentrator
, *service
;
88 const char *ifname
, *configname
;
91 struct clockinfo clockinfo
;
95 access_concentrator
= NULL
;
98 while ((c
= getopt(argc
, argv
, "vde:f:s:a:n:")) != -1)
109 eth_if_name
= optarg
;
121 access_concentrator
= optarg
;
125 if (strcmp(optarg
, "1") == 0)
127 else if (strcmp(optarg
, "2") == 0)
130 fprintf(stderr
, "bad argument \"%s\" to -n (only 1 or two allowed)\n",
143 if (errs
|| argc
< 1)
148 /* use a random AF to create the socket */
149 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
150 err(EX_UNAVAILABLE
, "ifconfig: socket");
156 struct pppoediscparms parms
;
159 memset(&parms
, 0, sizeof parms
);
160 strncpy(parms
.ifname
, ifname
, sizeof(parms
.ifname
));
161 strncpy(parms
.eth_ifname
, eth_if_name
, sizeof(parms
.eth_ifname
));
162 if (access_concentrator
) {
163 parms
.ac_name
= access_concentrator
;
164 parms
.ac_name_len
= strlen(access_concentrator
);
167 parms
.service_name
= service
;
168 parms
.service_name_len
= strlen(service
);
171 e
= ioctl(s
, PPPOESETPARMS
, &parms
);
173 print_error(ifname
, e
, "PPPOESETPARMS");
178 /* print DNS addresses */
180 struct spppdnsaddrs addrs
;
181 memset(&addrs
, 0, sizeof addrs
);
182 strncpy(addrs
.ifname
, ifname
, sizeof addrs
.ifname
);
183 e
= ioctl(s
, SPPPGETDNSADDRS
, &addrs
);
185 print_error(ifname
, e
, "SPPPGETDNSADDRS");
187 printf("%d.%d.%d.%d\n",
188 (addrs
.dns
[0] >> 24) & 0xff,
189 (addrs
.dns
[0] >> 16) & 0xff,
190 (addrs
.dns
[0] >> 8) & 0xff,
191 addrs
.dns
[0] & 0xff);
193 printf("%d.%d.%d.%d\n",
194 (addrs
.dns
[1] >> 24) & 0xff,
195 (addrs
.dns
[1] >> 16) & 0xff,
196 (addrs
.dns
[1] >> 8) & 0xff,
197 addrs
.dns
[1] & 0xff);
201 /* dump PPPoE session state */
202 struct pppoeconnectionstate state
;
205 memset(&state
, 0, sizeof state
);
206 strncpy(state
.ifname
, ifname
, sizeof state
.ifname
);
207 e
= ioctl(s
, PPPOEGETSESSION
, &state
);
209 print_error(ifname
, e
, "PPPOEGETSESSION");
211 printf("%s:\tstate = ", ifname
);
212 switch(state
.state
) {
213 case PPPOE_STATE_INITIAL
:
214 printf("initial\n"); break;
215 case PPPOE_STATE_PADI_SENT
:
216 printf("PADI sent\n"); break;
217 case PPPOE_STATE_PADR_SENT
:
218 printf("PADR sent\n"); break;
219 case PPPOE_STATE_SESSION
:
220 printf("session\n"); break;
221 case PPPOE_STATE_CLOSING
:
222 printf("closing\n"); break;
224 printf("\tSession ID: 0x%x\n", state
.session_id
);
225 printf("\tPADI retries: %d\n", state
.padi_retry_no
);
226 printf("\tPADR retries: %d\n", state
.padr_retry_no
);
232 memset(&spr
, 0, sizeof spr
);
233 strncpy(spr
.ifname
, ifname
, sizeof spr
.ifname
);
234 memset(&lcp
, 0, sizeof lcp
);
235 strncpy(lcp
.ifname
, ifname
, sizeof lcp
.ifname
);
236 memset(&status
, 0, sizeof status
);
237 strncpy(status
.ifname
, ifname
, sizeof status
.ifname
);
238 memset(&timeout
, 0, sizeof timeout
);
239 strncpy(timeout
.ifname
, ifname
, sizeof timeout
.ifname
);
240 memset(&authfailstats
, 0, sizeof &authfailstats
);
241 strncpy(authfailstats
.ifname
, ifname
, sizeof authfailstats
.ifname
);
242 memset(&authfailset
, 0, sizeof authfailset
);
243 strncpy(authfailset
.ifname
, ifname
, sizeof authfailset
.ifname
);
244 memset(&dnssettings
, 0, sizeof dnssettings
);
245 strncpy(dnssettings
.ifname
, ifname
, sizeof dnssettings
.ifname
);
246 memset(&keepalivesettings
, 0, sizeof keepalivesettings
);
247 strncpy(keepalivesettings
.ifname
, ifname
, sizeof keepalivesettings
.ifname
);
250 mib
[1] = KERN_CLOCKRATE
;
251 len
= sizeof(clockinfo
);
252 if(sysctl(mib
, 2, &clockinfo
, &len
, NULL
, 0) == -1)
254 fprintf(stderr
, "error, cannot sysctl kern.clockrate!\n");
260 if (argc
== 0 && !(dns1
||dns2
) && !configname
) {
263 /* first pass, get name lengths */
264 if (ioctl(s
, SPPPGETAUTHCFG
, &spr
) == -1)
265 err(EX_OSERR
, "SPPPGETAUTHCFG");
266 /* now allocate buffers for strings */
267 if (spr
.myname_length
)
268 if ((spr
.myname
= malloc(spr
.myname_length
)) == NULL
)
270 if (spr
.hisname_length
)
271 if ((spr
.hisname
= malloc(spr
.hisname_length
)) == NULL
)
273 /* second pass: get names too */
274 if (ioctl(s
, SPPPGETAUTHCFG
, &spr
) == -1)
275 err(EX_OSERR
, "SPPPGETAUTHCFG");
277 if (ioctl(s
, SPPPGETLCPCFG
, &lcp
) == -1)
278 err(EX_OSERR
, "SPPPGETLCPCFG");
279 if (ioctl(s
, SPPPGETSTATUS
, &status
) == -1)
280 err(EX_OSERR
, "SPPPGETSTATUS");
281 if (ioctl(s
, SPPPGETIDLETO
, &timeout
) == -1)
282 err(EX_OSERR
, "SPPPGETIDLETO");
283 if (ioctl(s
, SPPPGETAUTHFAILURES
, &authfailstats
) == -1)
284 err(EX_OSERR
, "SPPPGETAUTHFAILURES");
285 if (ioctl(s
, SPPPGETKEEPALIVE
, &keepalivesettings
) == -1)
286 err(EX_OSERR
, "SPPPGETKEEPALIVE");
288 print_vals(ifname
, status
.phase
, &spr
, lcp
.lcp_timeout
,
289 timeout
.idle_seconds
, authfailstats
.auth_failures
,
290 authfailstats
.max_failures
,
291 keepalivesettings
.maxalive
,
292 keepalivesettings
.max_noreceive
);
294 if (spr
.hisname
) free(spr
.hisname
);
295 if (spr
.myname
) free(spr
.myname
);
299 /* first load the config file, then parse command line args */
300 if (configname
&& (fp
= fopen(configname
, "r")))
301 while ((line
= fparseln(fp
, NULL
, NULL
, NULL
,
302 FPARSELN_UNESCALL
)) != NULL
) {
304 pppoectl_argument(line
);
306 * We do not free(line) here, because we
307 * still have references to parts of the
308 * string collected in the various ioctl
309 * argument structures (and need those).
310 * Yes, this is a memory leak.
311 * We could copy the partial strings instead,
312 * and free those later - but this is a one-shot
313 * program and memory will be freed at process
320 pppoectl_argument(argv
[0]);
327 if (ioctl(s
, SPPPSETAUTHCFG
, &spr
) == -1)
328 err(EX_OSERR
, "SPPPSETAUTHCFG");
331 if (ioctl(s
, SPPPSETLCPCFG
, &lcp
) == -1)
332 err(EX_OSERR
, "SPPPSETLCPCFG");
335 if (ioctl(s
, SPPPSETIDLETO
, &timeout
) == -1)
336 err(EX_OSERR
, "SPPPSETIDLETO");
338 if (set_auth_failure
) {
339 if (ioctl(s
, SPPPSETAUTHFAILURE
, &authfailset
) == -1)
340 err(EX_OSERR
, "SPPPSETAUTHFAILURE");
342 if (clear_auth_failure_count
&& !(set_auth
|| set_auth_failure
)) {
344 * We want to clear the auth failure count, but did not
345 * do that implicitly by setting authentication - so
346 * do a zero-effect auth setting change
348 if (ioctl(s
, SPPPGETAUTHFAILURES
, &authfailstats
) == -1)
349 err(EX_OSERR
, "SPPPGETAUTHFAILURES");
350 authfailset
.max_failures
= authfailstats
.max_failures
;
351 if (ioctl(s
, SPPPSETAUTHFAILURE
, &authfailset
) == -1)
352 err(EX_OSERR
, "SPPPSETAUTHFAILURE");
355 if (ioctl(s
, SPPPSETDNSOPTS
, &dnssettings
) == -1)
356 err(EX_OSERR
, "SPPPSETDNSOPTS");
359 if (ioctl(s
, SPPPGETKEEPALIVE
, &keepalivesettings
) == -1)
360 err(EX_OSERR
, "SPPPGETKEEPALIVE");
361 if (max_noreceive
>= 0)
362 keepalivesettings
.max_noreceive
= max_noreceive
;
364 keepalivesettings
.maxalive
= maxalive
;
365 if (ioctl(s
, SPPPSETKEEPALIVE
, &keepalivesettings
) == -1)
366 err(EX_OSERR
, "SPPPSETKEEPALIVE");
370 if (ioctl(s
, SPPPGETAUTHFAILURES
, &authfailstats
) == -1)
371 err(EX_OSERR
, "SPPPGETAUTHFAILURES");
372 if (ioctl(s
, SPPPGETKEEPALIVE
, &keepalivesettings
) == -1)
373 err(EX_OSERR
, "SPPPGETKEEPALIVE");
374 print_vals(ifname
, status
.phase
, &spr
, lcp
.lcp_timeout
,
375 timeout
.idle_seconds
, authfailstats
.auth_failures
,
376 authfailstats
.max_failures
,
377 keepalivesettings
.maxalive
,
378 keepalivesettings
.max_noreceive
);
385 pppoectl_argument(char *arg
)
390 #define startswith(a,s) strncmp(a, s, (off = strlen(s))) == 0
391 if (startswith(arg
, "authproto=")) {
393 if (strcmp(cp
, "pap") == 0)
395 spr
.hisauth
= SPPP_AUTHPROTO_PAP
;
396 else if (strcmp(cp
, "chap") == 0)
397 spr
.myauth
= spr
.hisauth
= SPPP_AUTHPROTO_CHAP
;
398 else if (strcmp(cp
, "none") == 0)
399 spr
.myauth
= spr
.hisauth
= SPPP_AUTHPROTO_NONE
;
401 errx(EX_DATAERR
, "bad auth proto: %s", cp
);
403 } else if (startswith(arg
, "myauthproto=")) {
405 if (strcmp(cp
, "pap") == 0)
406 spr
.myauth
= SPPP_AUTHPROTO_PAP
;
407 else if (strcmp(cp
, "chap") == 0)
408 spr
.myauth
= SPPP_AUTHPROTO_CHAP
;
409 else if (strcmp(cp
, "none") == 0)
410 spr
.myauth
= SPPP_AUTHPROTO_NONE
;
412 errx(EX_DATAERR
, "bad auth proto: %s", cp
);
414 } else if (startswith(arg
, "myauthname=")) {
415 spr
.myname
= arg
+ off
;
416 spr
.myname_length
= strlen(spr
.myname
)+1;
418 } else if (startswith(arg
, "myauthsecret=") || startswith(arg
, "myauthkey=")) {
419 spr
.mysecret
= arg
+ off
;
420 spr
.mysecret_length
= strlen(spr
.mysecret
)+1;
422 } else if (startswith(arg
, "hisauthproto=")) {
424 if (strcmp(cp
, "pap") == 0)
425 spr
.hisauth
= SPPP_AUTHPROTO_PAP
;
426 else if (strcmp(cp
, "chap") == 0)
427 spr
.hisauth
= SPPP_AUTHPROTO_CHAP
;
428 else if (strcmp(cp
, "none") == 0)
429 spr
.hisauth
= SPPP_AUTHPROTO_NONE
;
431 errx(EX_DATAERR
, "bad auth proto: %s", cp
);
433 } else if (startswith(arg
, "hisauthname=")) {
434 spr
.hisname
= arg
+ off
;
435 spr
.hisname_length
= strlen(spr
.hisname
)+1;
437 } else if (startswith(arg
, "hisauthsecret=") || startswith(arg
, "hisauthkey=")) {
438 spr
.hissecret
= arg
+ off
;
439 spr
.hissecret_length
= strlen(spr
.hissecret
)+1;
441 } else if (startswith(arg
, "max-noreceive=")) {
442 max_noreceive
= atoi(arg
+off
);
443 if (max_noreceive
< 0) {
445 "max-noreceive value must be at least 0\n");
450 } else if (startswith(arg
, "max-alive-missed=")) {
451 maxalive
= atoi(arg
+off
);
454 "max-alive-missed value must be at least 0\n");
459 } else if (strcmp(arg
, "callin") == 0)
460 spr
.hisauthflags
|= SPPP_AUTHFLAG_NOCALLOUT
;
461 else if (strcmp(arg
, "always") == 0)
462 spr
.hisauthflags
&= ~SPPP_AUTHFLAG_NOCALLOUT
;
463 else if (strcmp(arg
, "norechallenge") == 0)
464 spr
.hisauthflags
|= SPPP_AUTHFLAG_NORECHALLENGE
;
465 else if (strcmp(arg
, "rechallenge") == 0)
466 spr
.hisauthflags
&= ~SPPP_AUTHFLAG_NORECHALLENGE
;
468 else if (strcmp(arg
, "enable-vj") == 0)
469 spr
.defs
.enable_vj
= 1;
470 else if (strcmp(arg
, "disable-vj") == 0)
471 spr
.defs
.enable_vj
= 0;
473 else if (startswith(arg
, "lcp-timeout=")) {
474 int timeout_arg
= atoi(arg
+off
);
475 if ((timeout_arg
> 20000) || (timeout_arg
<= 0))
476 errx(EX_DATAERR
, "bad lcp timeout value: %s",
478 lcp
.lcp_timeout
= timeout_arg
* hz
/ 1000;
480 } else if (startswith(arg
, "idle-timeout=")) {
481 timeout
.idle_seconds
= (time_t)atol(arg
+off
);
483 } else if (startswith(arg
, "max-auth-failure=")) {
484 authfailset
.max_failures
= atoi(arg
+off
);
485 set_auth_failure
= 1;
486 } else if (strcmp(arg
, "clear-auth-failure") == 0) {
487 clear_auth_failure_count
= 1;
488 } else if (startswith(arg
, "query-dns=")) {
489 dnssettings
.query_dns
= atoi(arg
+off
);
492 errx(EX_DATAERR
, "bad parameter: \"%s\"", arg
);
498 const char * prog
= getprogname();
501 " %s [-f config] ifname [...]\n"
502 " %s [-v] ifname [{my|his}auth{proto|name|secret}=...] \\\n"
503 " [callin] [always] [{no}rechallenge]\n"
505 " to set authentication names, passwords\n"
506 " and (optional) paramaters\n"
507 " %s [-v] ifname lcp-timeout=ms|idle-timeout=s|\n"
508 " max-noreceive=s|max-alive-missed=cnt|\n"
509 " max-auth-failure=count|clear-auth-failure\n"
510 " to set general parameters\n"
512 " %s -e ethernet-ifname ifname\n"
513 " to connect an ethernet interface for PPPoE\n"
514 " %s [-a access-concentrator-name] [-s service-name] ifname\n"
515 " to specify (optional) data for PPPoE sessions\n"
517 " to dump the current PPPoE session state\n"
518 " %s -n (1|2) ifname\n"
519 " to print DNS addresses retrieved via query-dns\n"
520 , prog
, prog
, prog
, prog
, prog
, prog
, prog
);
525 print_vals(const char *ifname
, int phase
, struct spppauthcfg
*sp
, int lcp_timeout
,
526 time_t idle_timeout
, int authfailures
, int max_auth_failures
,
527 u_int maxalive_cnt
, time_t max_noreceive_time
)
533 printf("%s:\tphase=%s\n", ifname
, phase_name(phase
));
535 printf("\tmyauthproto=%s myauthname=\"%s\"\n",
536 proto_name(sp
->myauth
),
540 printf("\thisauthproto=%s hisauthname=\"%s\"%s\n",
541 proto_name(sp
->hisauth
),
543 authflags(sp
->hisauthflags
));
546 if (sp
->defs
.pp_phase
> PHASE_DEAD
) {
547 send
= time(NULL
) - sp
->defs
.pp_last_sent
;
548 recv
= time(NULL
) - sp
->defs
.pp_last_recv
;
549 printf("\tidle_time=%ld\n", (send
<recv
)? send
: recv
);
553 printf("\tlcp timeout: %.3f s\n",
554 (double)lcp_timeout
/ hz
);
556 if (idle_timeout
!= 0)
557 printf("\tidle timeout = %lu s\n", (unsigned long)idle_timeout
);
559 printf("\tidle timeout = disabled\n");
561 if (authfailures
!= 0)
562 printf("\tauthentication failures = %d\n", authfailures
);
563 printf("\tmax-auth-failure = %d\n", max_auth_failures
);
565 printf("\tmax-noreceive = %ld seconds\n", (long)max_noreceive_time
);
566 printf("\tmax-alive-missed = %u unanswered echo requests\n", maxalive_cnt
);
569 printf("\tenable_vj: %s\n",
570 sp
->defs
.enable_vj
? "on" : "off");
575 phase_name(int phase
)
578 case SPPP_PHASE_DEAD
: return "dead";
579 case SPPP_PHASE_ESTABLISH
: return "establish";
580 case SPPP_PHASE_TERMINATE
: return "terminate";
581 case SPPP_PHASE_AUTHENTICATE
: return "authenticate";
582 case SPPP_PHASE_NETWORK
: return "network";
588 proto_name(int proto
)
592 case SPPP_AUTHPROTO_PAP
: return "pap";
593 case SPPP_AUTHPROTO_CHAP
: return "chap";
594 case SPPP_AUTHPROTO_NONE
: return "none";
596 snprintf(buf
, sizeof(buf
), "0x%x", (unsigned)proto
);
605 if (flags
& SPPP_AUTHFLAG_NOCALLOUT
)
606 strlcat(buf
, " callin", sizeof(buf
));
607 if (flags
& SPPP_AUTHFLAG_NORECHALLENGE
)
608 strlcat(buf
, " norechallenge", sizeof(buf
));
613 print_error(const char *ifname
, int error
, const char * str
)
616 fprintf(stderr
, "%s: interface not found\n", ifname
);
618 fprintf(stderr
, "%s: %s: %s\n", ifname
, str
, strerror(error
));