# CC = gcc
#
COPTS = -O2 -pipe -Wall -g
- LIBS =
+ LIBS = -lrt
# Uncomment the next line to include support for Microsoft's
# MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux.
endif
ifdef MPPE
CFLAGS += -DMPPE=1
+HEADERS += mppe.h
endif
endif
#LIBS += -lshadow $(LIBS)
endif
-ifneq ($(wildcard /usr/include/crypt.h),)
+ifneq ($(wildcard $(shell $(CC) --print-sysroot)/usr/include/crypt.h),)
CFLAGS += -DHAVE_CRYPT_H=1
LIBS += -lcrypt
endif
ifdef NEEDDES
ifndef USE_CRYPT
-CFLAGS += -I/usr/include/openssl
+CFLAGS += -I$(shell $(CC) --print-sysroot)/usr/include/openssl
LIBS += -lcrypto
else
CFLAGS += -DUSE_CRYPT=1
#include <netdb.h>
#include <utmp.h>
#include <pwd.h>
-#include <setjmp.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "atcp.h"
#endif
-static const char rcsid[] = RCSID;
/* interface vars */
char ifname[MAXIFNAMELEN]; /* Interface name */
static sigset_t signals_handled;
static int waiting;
-static sigjmp_buf sigjmp;
+static int sigpipe[2];
char **script_env; /* Env. variable values for scripts */
int s_env_nalloc; /* # words avail at script_env */
info("Starting link");
}
- gettimeofday(&start_time, NULL);
+ get_time(&start_time);
script_unsetenv("CONNECT_TIME");
script_unsetenv("BYTES_SENT");
script_unsetenv("BYTES_RCVD");
handle_events()
{
struct timeval timo;
+ unsigned char buf[16];
kill_link = open_ccp_flag = 0;
- if (sigsetjmp(sigjmp, 1) == 0) {
- sigprocmask(SIG_BLOCK, &signals_handled, NULL);
- if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {
- sigprocmask(SIG_UNBLOCK, &signals_handled, NULL);
- } else {
- waiting = 1;
- sigprocmask(SIG_UNBLOCK, &signals_handled, NULL);
- wait_input(timeleft(&timo));
- }
- }
+
+ /* alert via signal pipe */
+ waiting = 1;
+ /* flush signal pipe */
+ for (; read(sigpipe[0], buf, sizeof(buf)) > 0; );
+ add_fd(sigpipe[0]);
+ /* wait if necessary */
+ if (!(got_sighup || got_sigterm || got_sigusr2 || got_sigchld))
+ wait_input(timeleft(&timo));
waiting = 0;
+ remove_fd(sigpipe[0]);
+
calltimeout();
if (got_sighup) {
info("Hangup (SIGHUP)");
{
struct sigaction sa;
+ /* create pipe to wake up event handler from signal handler */
+ if (pipe(sigpipe) < 0)
+ fatal("Couldn't create signal pipe: %m");
+ fcntl(sigpipe[0], F_SETFD, fcntl(sigpipe[0], F_GETFD) | FD_CLOEXEC);
+ fcntl(sigpipe[1], F_SETFD, fcntl(sigpipe[1], F_GETFD) | FD_CLOEXEC);
+ fcntl(sigpipe[0], F_SETFL, fcntl(sigpipe[0], F_GETFL) | O_NONBLOCK);
+ fcntl(sigpipe[1], F_SETFL, fcntl(sigpipe[1], F_GETFL) | O_NONBLOCK);
+
/*
* Compute mask of all interesting signals and install signal handlers
* for each. Only one signal handler may be active at a time. Therefore,
set_ifunit(iskey)
int iskey;
{
+ char ifkey[32];
+
if (req_ifname[0] != '\0')
slprintf(ifname, sizeof(ifname), "%s", req_ifname);
else
slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
info("Using interface %s", ifname);
script_setenv("IFNAME", ifname, iskey);
+ slprintf(ifkey, sizeof(ifkey), "%d", ifunit);
+ script_setenv("UNIT", ifkey, iskey);
if (iskey) {
create_pidfile(getpid()); /* write pid to file */
create_linkpidfile(getpid());
{
if (!get_ppp_stats(u, &old_link_stats))
return;
- gettimeofday(&start_time, NULL);
+ get_time(&start_time);
}
/*
char numbuf[32];
if (!get_ppp_stats(u, &link_stats)
- || gettimeofday(&now, NULL) < 0)
+ || get_time(&now) < 0)
return;
link_connect_time = now.tv_sec - start_time.tv_sec;
link_stats_valid = 1;
fatal("Out of memory in timeout()!");
newp->c_arg = arg;
newp->c_func = func;
- gettimeofday(&timenow, NULL);
+ get_time(&timenow);
newp->c_time.tv_sec = timenow.tv_sec + secs;
newp->c_time.tv_usec = timenow.tv_usec + usecs;
if (newp->c_time.tv_usec >= 1000000) {
while (callout != NULL) {
p = callout;
- if (gettimeofday(&timenow, NULL) < 0)
+ if (get_time(&timenow) < 0)
fatal("Failed to get time of day: %m");
if (!(p->c_time.tv_sec < timenow.tv_sec
|| (p->c_time.tv_sec == timenow.tv_sec
if (callout == NULL)
return NULL;
- gettimeofday(&timenow, NULL);
+ get_time(&timenow);
tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
if (tvp->tv_usec < 0) {
kill_my_pg(sig);
notify(sigreceived, sig);
if (waiting)
- siglongjmp(sigjmp, 1);
+ write(sigpipe[1], &sig, sizeof(sig));
}
kill_my_pg(sig);
notify(sigreceived, sig);
if (waiting)
- siglongjmp(sigjmp, 1);
+ write(sigpipe[1], &sig, sizeof(sig));
}
{
got_sigchld = 1;
if (waiting)
- siglongjmp(sigjmp, 1);
+ write(sigpipe[1], &sig, sizeof(sig));
}
{
got_sigusr2 = 1;
if (waiting)
- siglongjmp(sigjmp, 1);
+ write(sigpipe[1], &sig, sizeof(sig));
}
/* Executing in the child */
sys_close();
#ifdef USE_TDB
- tdb_close(pppdb);
+ if (pppdb != NULL)
+ tdb_close(pppdb);
#endif
/* make sure infd, outfd and errfd won't get tromped on below */
#define __PPPD_H__
#include <stdio.h> /* for FILE */
+#include <stdlib.h> /* for encrypt */
+#include <unistd.h> /* for setkey */
#include <limits.h> /* for NGROUPS_MAX */
#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
#include <sys/types.h> /* for u_int32_t, if defined */
/* Create default route through i/f */
int cifdefaultroute __P((int, u_int32_t, u_int32_t));
/* Delete default route through i/f */
+#ifdef INET6
+int sif6defaultroute __P((int, eui64_t, eui64_t));
+ /* Create default IPv6 route through i/f */
+int cif6defaultroute __P((int, eui64_t, eui64_t));
+ /* Delete default IPv6 route through i/f */
+#endif
int sifproxyarp __P((int, u_int32_t));
/* Add proxy ARP entry for peer */
int cifproxyarp __P((int, u_int32_t));
#endif
int get_if_hwaddr __P((u_char *addr, char *name));
char *get_first_ethernet __P((void));
+ int get_time __P((struct timeval *));
+ /* Get current time, monotonic if possible. */
/* Procedures exported from options.c */
int setipaddr __P((char *, char **, int)); /* Set local/remote ip addresses */
#define MAX_ADDR_LEN 7
#endif
-#if __GLIBC__ >= 2
+#if !defined(__GLIBC__) || __GLIBC__ >= 2
#include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
#include <net/if.h>
#include <net/if_arp.h>
eui64_copy(eui64, sin6.s6_addr32[2]); \
} while (0)
+static const eui64_t nulleui64;
#endif /* INET6 */
/* We can get an EIO error on an ioctl if the modem has hung up */
static int if_is_up; /* Interface has been marked up */
static int if6_is_up; /* Interface has been marked up for IPv6, to help differentiate */
static int have_default_route; /* Gateway for default route added */
+static int have_default_route6; /* Gateway for default IPv6 route added */
static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
static char proxy_arp_dev[16]; /* Device for proxy arp entry */
static u_int32_t our_old_addr; /* for detecting address changes */
static int open_route_table (void);
static int read_route_table (struct rtentry *rt);
static int defaultroute_exists (struct rtentry *rt, int metric);
+static int defaultroute6_exists (struct in6_rtmsg *rt, int metric);
static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
char *name, int namelen);
static void decode_version (char *buf, int *version, int *mod, int *patch);
*/
if (have_default_route)
cifdefaultroute(0, 0, 0);
+#ifdef INET6
+ if (have_default_route6)
+ cif6defaultroute(0, nulleui64, nulleui64);
+#endif
if (has_proxy_arp)
cifproxyarp(0, proxy_arp_addr);
char t[MAXIFNAMELEN];
memset(&ifr, 0, sizeof(struct ifreq));
slprintf(t, sizeof(t), "%s%d", PPP_DRV_NAME, ifunit);
- strncpy(ifr.ifr_name, t, IF_NAMESIZE);
- strncpy(ifr.ifr_newname, req_ifname, IF_NAMESIZE);
+ strlcpy(ifr.ifr_name, t, IF_NAMESIZE);
+ strlcpy(ifr.ifr_newname, req_ifname, IF_NAMESIZE);
x = ioctl(sock_fd, SIOCSIFNAME, &ifr);
if (x < 0)
error("Couldn't rename interface %s to %s: %m", t, req_ifname);
return 1;
}
+#ifdef INET6
+/*
+ * /proc/net/ipv6_route parsing stuff.
+ */
+static int route_dest_plen_col;
+static int open_route6_table (void);
+static int read_route6_table (struct in6_rtmsg *rt);
+
+/********************************************************************
+ *
+ * open_route6_table - open the interface to the route table
+ */
+static int open_route6_table (void)
+{
+ char *path;
+
+ close_route_table();
+
+ path = path_to_procfs("/net/ipv6_route");
+ route_fd = fopen (path, "r");
+ if (route_fd == NULL) {
+ error("can't open routing table %s: %m", path);
+ return 0;
+ }
+
+ /* default to usual columns */
+ route_dest_col = 0;
+ route_dest_plen_col = 1;
+ route_gw_col = 4;
+ route_metric_col = 5;
+ route_flags_col = 8;
+ route_dev_col = 9;
+ route_num_cols = 10;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * read_route6_table - read the next entry from the route table
+ */
+
+static void hex_to_in6_addr(struct in6_addr *addr, const char *s)
+{
+ char hex8[9];
+ unsigned i;
+ uint32_t v;
+
+ hex8[8] = 0;
+ for (i = 0; i < 4; i++) {
+ memcpy(hex8, s + 8*i, 8);
+ v = strtoul(hex8, NULL, 16);
+ addr->s6_addr32[i] = v;
+ }
+}
+
+static int read_route6_table(struct in6_rtmsg *rt)
+{
+ char *cols[ROUTE_MAX_COLS], *p;
+ int col;
+
+ memset (rt, '\0', sizeof (struct in6_rtmsg));
+
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
+ return 0;
+
+ p = route_buffer;
+ for (col = 0; col < route_num_cols; ++col) {
+ cols[col] = strtok(p, route_delims);
+ if (cols[col] == NULL)
+ return 0; /* didn't get enough columns */
+ p = NULL;
+ }
+
+ hex_to_in6_addr(&rt->rtmsg_dst, cols[route_dest_col]);
+ rt->rtmsg_dst_len = strtoul(cols[route_dest_plen_col], NULL, 16);
+ hex_to_in6_addr(&rt->rtmsg_gateway, cols[route_gw_col]);
+
+ rt->rtmsg_metric = strtoul(cols[route_metric_col], NULL, 16);
+ rt->rtmsg_flags = strtoul(cols[route_flags_col], NULL, 16);
+ rt->rtmsg_ifindex = if_nametoindex(cols[route_dev_col]);
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * defaultroute6_exists - determine if there is a default route
+ */
+
+static int defaultroute6_exists (struct in6_rtmsg *rt, int metric)
+{
+ int result = 0;
+
+ if (!open_route6_table())
+ return 0;
+
+ while (read_route6_table(rt) != 0) {
+ if ((rt->rtmsg_flags & RTF_UP) == 0)
+ continue;
+
+ if (rt->rtmsg_dst_len != 0)
+ continue;
+ if (rt->rtmsg_dst.s6_addr32[0] == 0L
+ && rt->rtmsg_dst.s6_addr32[1] == 0L
+ && rt->rtmsg_dst.s6_addr32[2] == 0L
+ && rt->rtmsg_dst.s6_addr32[3] == 0L
+ && (metric < 0 || rt->rtmsg_metric == metric)) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/********************************************************************
+ *
+ * sif6defaultroute - assign a default route through the address given.
+ *
+ * If the global default_rt_repl_rest flag is set, then this function
+ * already replaced the original system defaultroute with some other
+ * route and it should just replace the current defaultroute with
+ * another one, without saving the current route. Use: demand mode,
+ * when pppd sets first a defaultroute it it's temporary ppp0 addresses
+ * and then changes the temporary addresses to the addresses for the real
+ * ppp connection when it has come up.
+ */
+
+int sif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
+{
+ struct in6_rtmsg rt;
+ char buf[IF_NAMESIZE];
+
+ if (defaultroute6_exists(&rt, dfl_route_metric) &&
+ rt.rtmsg_ifindex != if_nametoindex(ifname)) {
+ if (rt.rtmsg_flags & RTF_GATEWAY)
+ error("not replacing existing default route via gateway");
+ else
+ error("not replacing existing default route through %s",
+ if_indextoname(rt.rtmsg_ifindex, buf));
+ return 0;
+ }
+
+ memset (&rt, 0, sizeof (rt));
+
+ rt.rtmsg_ifindex = if_nametoindex(ifname);
+ rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+ rt.rtmsg_dst_len = 0;
+
+ rt.rtmsg_flags = RTF_UP;
+ if (ioctl(sock6_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+
+ have_default_route6 = 1;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cif6defaultroute - delete a default route through the address given.
+ */
+
+int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
+{
+ struct in6_rtmsg rt;
+
+ have_default_route6 = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+
+ rt.rtmsg_ifindex = if_nametoindex(ifname);
+ rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+ rt.rtmsg_dst_len = 0;
+
+ rt.rtmsg_flags = RTF_UP;
+ if (ioctl(sock6_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif /* INET6 */
+
/********************************************************************
*
* sifproxyarp - Make a proxy ARP entry for the peer.
return 1;
}
#endif
+
+ /********************************************************************
+ *
+ * get_time - Get current time, monotonic if possible.
+ */
+ int
+ get_time(struct timeval *tv)
+ {
+ /* Old glibc (< 2.3.4) does define CLOCK_MONOTONIC, but kernel may have it.
+ * Runtime checking makes it safe. */
+ #ifndef CLOCK_MONOTONIC
+ #define CLOCK_MONOTONIC 1
+ #endif
+ static int monotonic = -1;
+ struct timespec ts;
+ int ret;
+
+ if (monotonic) {
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret == 0) {
+ monotonic = 1;
+ if (tv) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return ret;
+ } else if (monotonic > 0)
+ return ret;
+
+ monotonic = 0;
+ warn("Couldn't use monotonic clock source: %m");
+ }
+
+ return gettimeofday(tv, NULL);
+ }
#include <sys/dlpi.h>
#include <sys/stat.h>
#include <sys/mkdev.h>
+ #include <sys/time.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/route.h>
#define UDP6_DEV_NAME "/dev/udp6"
#endif /* !defined(UDP6_DEV_NAME) && defined(SOL2) */
-static const char rcsid[] = RCSID;
#if defined(SOL2)
/*
static int ip6muxid = -1; /* Multiplexer file descriptor */
static int if6_is_up = 0; /* IPv6 interface has been marked up */
+#define IN6_SOCKADDR_FROM_EUI64(s, eui64) do { \
+ (s)->sin6_family = AF_INET6; \
+ (s)->sin6_addr.s6_addr32[0] = htonl(0xfe800000); \
+ eui64_copy(eui64, (s)->sin6_addr.s6_addr32[2]); \
+ } while(0)
+
#define _IN6_LLX_FROM_EUI64(l, s, eui64, as) do { \
s->sin6_addr.s6_addr32[0] = htonl(as); \
eui64_copy(eui64, s->sin6_addr.s6_addr32[2]); \
l.lifr_addr = laddr; \
} while (0)
+#define _IN6A_LLX_FROM_EUI64(s, eui64, as) do { \
+ s->s6_addr32[0] = htonl(as); \
+ eui64_copy(eui64, s->s6_addr32[2]); \
+ } while (0)
+
#define IN6_LLADDR_FROM_EUI64(l, s, eui64) \
_IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000)
#define IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
_IN6_LLX_FROM_EUI64(l, s, eui64, 0)
+#define IN6A_LLADDR_FROM_EUI64(s, eui64) \
+ _IN6A_LLX_FROM_EUI64(s, eui64, 0xfe800000)
+
#endif /* defined(INET6) && defined(SOL2) */
#if defined(INET6) && defined(SOL2)
static int if_is_up; /* Interface has been marked up */
static u_int32_t remote_addr; /* IP address of peer */
static u_int32_t default_route_gateway; /* Gateway for default route added */
+static eui64_t default_route_gateway6; /* Gateway for default IPv6 route added */
static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
/* Prototypes for procedures local to this file. */
sifdown(0);
if (default_route_gateway)
cifdefaultroute(0, default_route_gateway, default_route_gateway);
+ if (default_route_gateway6.e32[0] != 0 || default_route_gateway6.e32[1] != 0)
+ cif6defaultroute(0, default_route_gateway6, default_route_gateway6);
if (proxy_arp_addr)
cifproxyarp(0, proxy_arp_addr);
#if defined(SOL2)
return 1;
}
+/*
+ * sif6defaultroute - assign a default route through the address given.
+ */
+int
+sif6defaultroute(u, l, g)
+ int u;
+ eui64_t l, g;
+{
+ struct {
+ struct rt_msghdr rtm;
+ struct sockaddr_in6 dst;
+ struct sockaddr_in6 gw;
+ } rmsg;
+ static int seq;
+ int rtsock;
+
+#if defined(__USLC__)
+ g = l; /* use the local address as gateway */
+#endif
+ memset(&rmsg, 0, sizeof(rmsg));
+
+ rmsg.rtm.rtm_msglen = sizeof (rmsg);
+ rmsg.rtm.rtm_version = RTM_VERSION;
+ rmsg.rtm.rtm_type = RTM_ADD;
+ rmsg.rtm.rtm_flags = RTF_GATEWAY;
+ rmsg.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ rmsg.rtm.rtm_pid = getpid();
+ rmsg.rtm.rtm_seq = seq++;
+
+ rmsg.dst.sin6_family = AF_INET6;
+
+ rmsg.gw.sin6_family = AF_INET6;
+ IN6_SOCKADDR_FROM_EUI64(&rmsg.gw, g);
+
+ rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
+
+ if (rtsock < 0) {
+ error("Can't add default route: %m");
+ return 0;
+ }
+
+ if (write(rtsock, &rmsg, sizeof(rmsg)) < 0)
+ error("Can't add default route: %m");
+
+ close(rtsock);
+
+ default_route_gateway6 = g;
+ return 1;
+}
+
+/*
+ * cif6defaultroute - delete a default route through the address given.
+ */
+int
+cif6defaultroute(u, l, g)
+ int u;
+ eui64_t l, g;
+{
+ /* No need to do this on Solaris; the kernel deletes the
+ route when the interface goes down. */
+ memset(&default_route_gateway6, 0, sizeof(default_route_gateway6));
+ return 1;
+}
+
#endif /* defined(SOL2) && defined(INET6) */
return 1;
}
+
+ /********************************************************************
+ *
+ * get_time - Get current time, monotonic if possible.
+ */
+ int
+ get_time(struct timeval *tv)
+ {
+ return gettimeofday(tv, NULL);
+ }
#include <netdb.h>
#include <utmp.h>
#include <pwd.h>
-#include <setjmp.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
pty_readable = stdin_readable = 1;
ilevel = olevel = 0;
- gettimeofday(&levelt, NULL);
+ get_time(&levelt);
if (max_data_rate) {
max_level = max_data_rate / 10;
if (max_level < 100)
int nbt;
struct timeval now;
- gettimeofday(&now, NULL);
+ get_time(&now);
dt = (now.tv_sec - levelt.tv_sec
+ (now.tv_usec - levelt.tv_usec) / 1e6);
nbt = (int)(dt * max_data_rate);