Beispiel #1
0
static void set_banner(struct openconnect_info *vpninfo)
{
	char *banner, *legacy_banner, *q;
	const char *p;

	if (!vpninfo->banner || !(banner = malloc(strlen(vpninfo->banner)+1))) {
		script_setenv(vpninfo, "CISCO_BANNER", NULL, 0);
		return;
	}
	p = vpninfo->banner;
	q = banner;

	while (*p) {
		if (*p == '%' && isxdigit((int)(unsigned char)p[1]) &&
		    isxdigit((int)(unsigned char)p[2])) {
			*(q++) = unhex(p + 1);
			p += 3;
		} else
			*(q++) = *(p++);
	}
	*q = 0;
	legacy_banner = openconnect_utf8_to_legacy(vpninfo, banner);
	script_setenv(vpninfo, "CISCO_BANNER", legacy_banner, 0);
	if (legacy_banner != banner)
		free(legacy_banner);

	free(banner);
}
Beispiel #2
0
/* Set up a traditional OS-based tunnel device, optionally specified in 'ifname'. */
int openconnect_setup_tun_device(struct openconnect_info *vpninfo,
				 const char *vpnc_script, const char *ifname)
{
	intptr_t tun_fd;
	char *legacy_ifname;

	UTF8CHECK(vpnc_script);
	UTF8CHECK(ifname);

	STRDUP(vpninfo->vpnc_script, vpnc_script);
	STRDUP(vpninfo->ifname, ifname);

	prepare_script_env(vpninfo);
	script_config_tun(vpninfo, "pre-init");

	tun_fd = os_setup_tun(vpninfo);
	if (tun_fd < 0)
		return tun_fd;

#ifdef _WIN32
	if (vpninfo->tun_idx != -1)
		script_setenv_int(vpninfo, "TUNIDX", vpninfo->tun_idx);
#endif
	legacy_ifname = openconnect_utf8_to_legacy(vpninfo, vpninfo->ifname);
	script_setenv(vpninfo, "TUNDEV", legacy_ifname, 0);
	if (legacy_ifname != vpninfo->ifname)
		free(legacy_ifname);
	script_config_tun(vpninfo, "connect");

	return openconnect_setup_tun_fd(vpninfo, tun_fd);
}
Beispiel #3
0
/*
 * The peer has been successfully authenticated using `protocol'.
 */
void
auth_peer_success(int unit, int protocol, char *name, int namelen)
{
    int bit;

    switch (protocol) {
    case PPP_CHAP:
	bit = CHAP_PEER;
	break;
    case PPP_PAP:
	bit = PAP_PEER;
	break;
    default:
	syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
	       protocol);
	return;
    }

    /*
     * Save the authenticated name of the peer for later.
     */
    if (namelen > sizeof(peer_authname) - 1)
	namelen = sizeof(peer_authname) - 1;
    BCOPY(name, peer_authname, namelen);
    peer_authname[namelen] = 0;

    /*
     * If we have overridden addresses based on auth info
     * then set that information now before continuing.
     */
    auth_set_ip_addr(unit);

    script_setenv("PEERNAME", peer_authname);

    /*
     * If there is no more authentication still to be done,
     * proceed to the network (or callback) phase.
     */
    if ((auth_pending[unit] &= ~bit) == 0)
        network_phase(unit);
}
Beispiel #4
0
static void setenv_cstp_opts(struct openconnect_info *vpninfo)
{
	char *env_buf;
	int buflen = 0;
	int bufofs = 0;
	struct oc_vpn_option *opt;

	for (opt = vpninfo->cstp_options; opt; opt = opt->next)
		buflen += 2 + strlen(opt->option) + strlen(opt->value);

	env_buf = malloc(buflen + 1);
	if (!env_buf)
		return;

	env_buf[buflen] = 0;

	for (opt = vpninfo->cstp_options; opt; opt = opt->next)
		bufofs += snprintf(env_buf + bufofs, buflen - bufofs,
				   "%s=%s\n", opt->option, opt->value);

	script_setenv(vpninfo, "CISCO_CSTP_OPTIONS", env_buf, 0);
	free(env_buf);
}
Beispiel #5
0
/*
 * Make a new bundle or join us to an existing bundle
 * if we are doing multilink.
 */
int
mp_join_bundle()
{
    lcp_options *go = &lcp_gotoptions[0];
    lcp_options *ho = &lcp_hisoptions[0];
    int unit, pppd_pid;
    int l;
    char *p;
    TDB_DATA key, pid, rec;

    if (!go->neg_mrru || !ho->neg_mrru) {
        /* not doing multilink */
        if (go->neg_mrru)
            notice("oops, multilink negotiated only for receive");
        multilink = 0;
        if (demand) {
            /* already have a bundle */
            cfg_bundle(0, 0, 0, 0);
            return 0;
        }
        make_new_bundle(0, 0, 0, 0);
        set_ifunit(1);
        return 0;
    }

    /*
     * Find the appropriate bundle or join a new one.
     * First we make up a name for the bundle.
     * The length estimate is worst-case assuming every
     * character has to be quoted.
     *
     * Note - RFC 1990 requires that an unnegotiated endpoint
     * discriminator value be equivalent to negotiating with class
     * zero.  Do not test ho->neg_endpoint here.
     */
    l = 4 * strlen(peer_authname) + 10;
    l += 3 * ho->endpoint.length + 8;
    if (bundle_name)
        l += 3 * strlen(bundle_name) + 2;
    bundle_id = malloc(l);
    if (bundle_id == NULL)
        novm("bundle identifier");

    p = bundle_id;
    p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
    *p++ = '/';
    p += slprintf(p, bundle_id+l-p, "%s", epdisc_to_str(&ho->endpoint));
    if (bundle_name)
        p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);
    dbglog("bundle_id = %s", bundle_id+7);

    /*
     * For demand mode, we only need to configure the bundle
     * and attach the link.
     */
    if (demand) {
        cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
        script_setenv("BUNDLE", bundle_id + 7, 1);
        return 0;
    }

    /*
     * Check if the bundle ID is already in the database.
     */
    unit = -1;
    tdb_writelock(pppdb);
    key.dptr = bundle_id;
    key.dsize = p - bundle_id;
    pid = tdb_fetch(pppdb, key);
    if (pid.dptr != NULL) {
        /* bundle ID exists, see if the pppd record exists */
        rec = tdb_fetch(pppdb, pid);
        if (rec.dptr != NULL) {
            /* it does, parse the interface number */
            parse_num(rec.dptr, "IFNAME=ppp", &unit);
            /* check the pid value */
            if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
                    || !process_exists(pppd_pid)
                    || !owns_unit(pid, unit))
                unit = -1;
            free(rec.dptr);
        }
        free(pid.dptr);
    }

    if (unit >= 0) {
        /* attach to existing unit */
        if (bundle_attach(unit)) {
            set_ifunit(0);
            script_setenv("BUNDLE", bundle_id + 7, 0);
            tdb_writeunlock(pppdb);
            info("Link attached to %s", ifname);
            return 1;
        }
        /* attach failed because bundle doesn't exist */
    }

    /* we have to make a new bundle */
    make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
    set_ifunit(1);
    script_setenv("BUNDLE", bundle_id + 7, 1);
    tdb_writeunlock(pppdb);
    info("New bundle %s created", ifname);
    return 0;
}
Beispiel #6
0
int
main(int argc, char *argv[])
{
    int i, n, fdflags;
    struct sigaction sa;
    FILE *iffile;
    char *p;
    struct passwd *pw;
    struct timeval timo;
    sigset_t mask;
    struct protent *protp;
    struct stat statbuf;
    int connect_attempts = 0;
    char numbuf[16];

    phase = PHASE_INITIALIZE;
    p = ttyname(0);
    if (p)
	strcpy(devnam, p);
    strcpy(default_devnam, devnam);

    script_env = NULL;

    /* Initialize syslog facilities */
#ifdef ULTRIX
    openlog("pppd", LOG_PID);
#else
    openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
    setlogmask(LOG_UPTO(LOG_INFO));
#endif

    if (gethostname(hostname, MAXNAMELEN) < 0 ) {
	option_error("Couldn't get hostname: %m");
	die(1);
    }
    hostname[MAXNAMELEN-1] = 0;

    uid = getuid();
    privileged = uid == 0;
    sprintf(numbuf, "%d", uid);
    script_setenv("UID", numbuf);

    /*
     * Initialize to the standard option set, then parse, in order,
     * the system options file, the user's options file,
     * the tty's options file, and the command line arguments.
     */
    for (i = 0; (protp = protocols[i]) != NULL; ++i)
        (*protp->init)(0);

    progname = *argv;

    if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
	|| !options_from_user())
	exit(1);
    scan_args(argc-1, argv+1);	/* look for tty name on command line */
    if (!options_for_tty()
	|| !parse_args(argc-1, argv+1))
	exit(1);

    /*
     * Check that we are running as root.
     */
    if (geteuid() != 0) {
	option_error("must be root to run %s, since it is not setuid-root",
		     argv[0]);
	die(1);
    }

    if (!ppp_available()) {
	option_error(no_ppp_msg);
	exit(1);
    }

    /*
     * Check that the options given are valid and consistent.
     */
    sys_check_options();
    auth_check_options();
    for (i = 0; (protp = protocols[i]) != NULL; ++i)
	if (protp->check_options != NULL)
	    (*protp->check_options)();
    if (demand && connector == 0) {
	option_error("connect script required for demand-dialling\n");
	exit(1);
    }

    script_setenv("DEVICE", devnam);
    sprintf(numbuf, "%d", baud_rate);
    script_setenv("SPEED", numbuf);

    /*
     * If the user has specified the default device name explicitly,
     * pretend they hadn't.
     */
    if (!default_device && strcmp(devnam, default_devnam) == 0)
	default_device = 1;
    if (default_device)
	nodetach = 1;

    /*
     * Initialize system-dependent stuff and magic number package.
     */
    sys_init();
    magic_init();
    if (debug)
	setlogmask(LOG_UPTO(LOG_DEBUG));

    /*
     * Detach ourselves from the terminal, if required,
     * and identify who is running us.
     */
    if (nodetach == 0)
	detach();
    pid = getpid();
    p = getlogin();
    stime = time(NULL);
    if (p == NULL) {
	pw = getpwuid(uid);
	if (pw != NULL && pw->pw_name != NULL)
	    p = pw->pw_name;
	else
	    p = "(unknown)";
    }
    syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d",
	   VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid);
  
    /*
     * Compute mask of all interesting signals and install signal handlers
     * for each.  Only one signal handler may be active at a time.  Therefore,
     * all other signals should be masked when any handler is executing.
     */
    sigemptyset(&mask);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGCHLD);

#define SIGNAL(s, handler)	{ \
	sa.sa_handler = handler; \
	if (sigaction(s, &sa, NULL) < 0) { \
	    syslog(LOG_ERR, "Couldn't establish signal handler (%d): %m", s); \
	    die(1); \
	} \
    }

    sa.sa_mask = mask;
    sa.sa_flags = 0;
    SIGNAL(SIGHUP, hup);		/* Hangup */
    SIGNAL(SIGINT, term);		/* Interrupt */
    SIGNAL(SIGTERM, term);		/* Terminate */
    SIGNAL(SIGCHLD, chld);

    SIGNAL(SIGUSR1, toggle_debug);	/* Toggle debug flag */
    SIGNAL(SIGUSR2, open_ccp);		/* Reopen CCP */

    /*
     * Install a handler for other signals which would otherwise
     * cause pppd to exit without cleaning up.
     */
    SIGNAL(SIGABRT, bad_signal);
    SIGNAL(SIGALRM, bad_signal);
    SIGNAL(SIGFPE, bad_signal);
    SIGNAL(SIGILL, bad_signal);
    SIGNAL(SIGPIPE, bad_signal);
    SIGNAL(SIGQUIT, bad_signal);
    SIGNAL(SIGSEGV, bad_signal);
#ifdef SIGBUS
    SIGNAL(SIGBUS, bad_signal);
#endif
#ifdef SIGEMT
    SIGNAL(SIGEMT, bad_signal);
#endif
#ifdef SIGPOLL
    SIGNAL(SIGPOLL, bad_signal);
#endif
#ifdef SIGPROF
    SIGNAL(SIGPROF, bad_signal);
#endif
#ifdef SIGSYS
    SIGNAL(SIGSYS, bad_signal);
#endif
#ifdef SIGTRAP
    SIGNAL(SIGTRAP, bad_signal);
#endif
#ifdef SIGVTALRM
    SIGNAL(SIGVTALRM, bad_signal);
#endif
#ifdef SIGXCPU
    SIGNAL(SIGXCPU, bad_signal);
#endif
#ifdef SIGXFSZ
    SIGNAL(SIGXFSZ, bad_signal);
#endif

    /*
     * Apparently we can get a SIGPIPE when we call syslog, if
     * syslogd has died and been restarted.  Ignoring it seems
     * be sufficient.
     */
    signal(SIGPIPE, SIG_IGN);

    /*
     * If we're doing dial-on-demand, set up the interface now.
     */
    if (demand) {
	/*
	 * Open the loopback channel and set it up to be the ppp interface.
	 */
	open_ppp_loopback();

	syslog(LOG_INFO, "Using interface ppp%d", ifunit);
	sprintf(ifname, "ppp%d", ifunit);
	script_setenv("IFNAME", ifname);

	create_pidfile();	/* write pid to file */

	/*
	 * Configure the interface and mark it up, etc.
	 */
	demand_conf();
    }

    for (;;) {

	need_holdoff = 1;

	if (demand) {
	    /*
	     * Don't do anything until we see some activity.
	     */
	    phase = PHASE_DORMANT;
	    kill_link = 0;
	    demand_unblock();
	    for (;;) {
		wait_loop_output(timeleft(&timo));
		calltimeout();
		if (kill_link) {
		    if (!persist)
			die(0);
		    kill_link = 0;
		}
		if (get_loop_output())
		    break;
		reap_kids();
	    }

	    /*
	     * Now we want to bring up the link.
	     */
	    demand_block();
	    syslog(LOG_INFO, "Starting link");
	}

	/*
	 * Lock the device if we've been asked to.
	 */
	if (lockflag && !default_device) {
	    if (lock(devnam) < 0)
		goto fail;
	    locked = 1;
	}

	/*
	 * Open the serial device and set it up to be the ppp interface.
	 * First we open it in non-blocking mode so we can set the
	 * various termios flags appropriately.  If we aren't dialling
	 * out and we want to use the modem lines, we reopen it later
	 * in order to wait for the carrier detect signal from the modem.
	 */
	while ((ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0)) < 0) {
	    if (errno != EINTR)
		syslog(LOG_ERR, "Failed to open %s: %m", devnam);
	    if (!persist || errno != EINTR)
		goto fail;
	}
	if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
	    || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
	    syslog(LOG_WARNING,
		   "Couldn't reset non-blocking mode on device: %m");

	hungup = 0;
	kill_link = 0;

	/*
	 * Do the equivalent of `mesg n' to stop broadcast messages.
	 */
	if (fstat(ttyfd, &statbuf) < 0
	    || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
	    syslog(LOG_WARNING,
		   "Couldn't restrict write permissions to %s: %m", devnam);
	} else
	    tty_mode = statbuf.st_mode;

	/* run connection script */
	if (connector && connector[0]) {
	    MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector));

	    /*
	     * Set line speed, flow control, etc.
	     * On most systems we set CLOCAL for now so that we can talk
	     * to the modem before carrier comes up.  But this has the
	     * side effect that we might miss it if CD drops before we
	     * get to clear CLOCAL below.  On systems where we can talk
	     * successfully to the modem with CLOCAL clear and CD down,
	     * we can clear CLOCAL at this point.
	     */
	    set_up_tty(ttyfd, 1);

	    /* drop dtr to hang up in case modem is off hook */
	    if (!default_device && modem) {
		setdtr(ttyfd, FALSE);
		sleep(1);
		setdtr(ttyfd, TRUE);
	    }

	    if (device_script(connector, ttyfd, ttyfd) < 0) {
		syslog(LOG_ERR, "Connect script failed");
		setdtr(ttyfd, FALSE);
		connect_attempts++;
		goto fail;
	    }


	    syslog(LOG_INFO, "Serial connection established.");
	    sleep(1);		/* give it time to set up its terminal */
	}

	connect_attempts = 0;	/* we made it through ok */

	/* set line speed, flow control, etc.; clear CLOCAL if modem option */
	set_up_tty(ttyfd, 0);

	/* reopen tty if necessary to wait for carrier */
	if (connector == NULL && modem) {
	    while ((i = open(devnam, O_RDWR)) < 0) {
		if (errno != EINTR)
		    syslog(LOG_ERR, "Failed to reopen %s: %m", devnam);
		if (!persist || errno != EINTR ||
			hungup || kill_link)
		    goto fail;
	    }
	    close(i);
	}

	/* run welcome script, if any */
	if (welcomer && welcomer[0]) {
	    if (device_script(welcomer, ttyfd, ttyfd) < 0)
		syslog(LOG_WARNING, "Welcome script failed");
	}

	/* set up the serial device as a ppp interface */
	establish_ppp(ttyfd);

	if (!demand) {
	    
	    syslog(LOG_INFO, "Using interface ppp%d", ifunit);
	    sprintf(ifname, "ppp%d", ifunit);
	    
	    create_pidfile();	/* write pid to file */

	    /* write interface unit number to file */
	    for (n = strlen(devnam); n > 0 ; n--)
		    if (devnam[n] == '/') { 
			    n++;
			    break;
		    }
	    sprintf(iffilename, "%s%s.if", _PATH_VARRUN, &devnam[n]);
	    if ((iffile = fopen(iffilename, "w")) != NULL) {
		fprintf(iffile, "ppp%d\n", ifunit);
		fclose(iffile);
	    } else {
		syslog(LOG_ERR, "Failed to create if file %s: %m", iffilename);
		iffilename[0] = 0;
	    }

	    script_setenv("IFNAME", ifname);
	}

	/*
	 * Start opening the connection and wait for
	 * incoming events (reply, timeout, etc.).
	 */
	syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam);
	stime = time(NULL);
	lcp_lowerup(0);
	lcp_open(0);		/* Start protocol */
	for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) {
	    wait_input(timeleft(&timo));
	    calltimeout();
	    get_input();
	    if (kill_link) {
		lcp_close(0, "User request");
		kill_link = 0;
	    }
	    if (open_ccp_flag) {
		if (phase == PHASE_NETWORK) {
		    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
		    (*ccp_protent.open)(0);
		}
		open_ccp_flag = 0;
	    }
	    reap_kids();	/* Don't leave dead kids lying around */
	}

	/*
	 * If we may want to bring the link up again, transfer
	 * the ppp unit back to the loopback.  Set the
	 * real serial device back to its normal mode of operation.
	 */
	clean_check();
	if (demand)
	    restore_loop();
	disestablish_ppp(ttyfd);

	/*
	 * Run disconnector script, if requested.
	 * XXX we may not be able to do this if the line has hung up!
	 */
	if (disconnector && !hungup) {
	    set_up_tty(ttyfd, 1);
	    if (device_script(disconnector, ttyfd, ttyfd) < 0) {
		syslog(LOG_WARNING, "disconnect script failed");
	    } else {
		syslog(LOG_INFO, "Serial link disconnected.");
	    }
	}

    fail:
	if (ttyfd >= 0)
	    close_tty();
	if (locked) {
	    unlock();
	    locked = 0;
	}

	if (!demand) {
	    if (pidfilename[0] != 0
		&& unlink(pidfilename) < 0 && errno != ENOENT) 
		syslog(LOG_WARNING, "unable to delete pid file: %m");
	    pidfilename[0] = 0;

	    if (iffile)
		    if (unlink(iffilename) < 0 && errno != ENOENT) 
			    syslog(LOG_WARNING, "unable to delete if file: %m");
	    iffilename[0] = 0;
	}

	/* limit to retries? */
	if (max_con_attempts)
	    if (connect_attempts >= max_con_attempts)
		break;

	if (!persist)
	    die(1);

	if (demand)
	    demand_discard();
	if (holdoff > 0 && need_holdoff) {
	    phase = PHASE_HOLDOFF;
	    TIMEOUT(holdoff_end, NULL, holdoff);
	    do {
		wait_time(timeleft(&timo));
		calltimeout();
		if (kill_link) {
		    if (!persist)
			die(0);
		    kill_link = 0;
		    phase = PHASE_DORMANT; /* allow signal to end holdoff */
		}
		reap_kids();
	    } while (phase == PHASE_HOLDOFF);
	}
    }

    die(0);
    return 0;
}
Beispiel #7
0
/**********************************************************************
 * %FUNCTION: PPPOEConnectDevice
 * %ARGUMENTS:
 * None
 * %RETURNS:
 * Non-negative if all goes well; -1 otherwise
 * %DESCRIPTION:
 * Connects PPPoE device.
 ***********************************************************************/
static int
PPPOEConnectDevice(void)
{
    struct sockaddr_pppox sp;

    strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
    if (existingSession) {
	unsigned int mac[ETH_ALEN];
	int i, ses;
	if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
		   &ses, &mac[0], &mac[1], &mac[2],
		   &mac[3], &mac[4], &mac[5]) != 7) {
	    fatal("Illegal value for rp_pppoe_sess option");
	}
	conn->session = htons(ses);
	for (i=0; i<ETH_ALEN; i++) {
	    conn->peerEth[i] = (unsigned char) mac[i];
	}
    } else {
	discovery(conn);
	if (conn->discoveryState != STATE_SESSION) {
	    error("Unable to complete PPPoE Discovery");
	    return -1;
	}
    }

    /* Set PPPoE session-number for further consumption */
    ppp_session_number = ntohs(conn->session);

    /* Make the session socket */
    conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
    if (conn->sessionSocket < 0) {
	error("Failed to create PPPoE socket: %m");
	return -1;
    }
    sp.sa_family = AF_PPPOX;
    sp.sa_protocol = PX_PROTO_OE;
    sp.sa_addr.pppoe.sid = conn->session;
    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);

    /* Set remote_number for ServPoET */
    sprintf(remote_number, "%02X:%02X:%02X:%02X:%02X:%02X",
	    (unsigned) conn->peerEth[0],
	    (unsigned) conn->peerEth[1],
	    (unsigned) conn->peerEth[2],
	    (unsigned) conn->peerEth[3],
	    (unsigned) conn->peerEth[4],
	    (unsigned) conn->peerEth[5]);

    warn("Connected to %02X:%02X:%02X:%02X:%02X:%02X via interface %s",
	 (unsigned) conn->peerEth[0],
	 (unsigned) conn->peerEth[1],
	 (unsigned) conn->peerEth[2],
	 (unsigned) conn->peerEth[3],
	 (unsigned) conn->peerEth[4],
	 (unsigned) conn->peerEth[5],
	 conn->ifName);

    script_setenv("MACREMOTE", remote_number, 0);

    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
		sizeof(struct sockaddr_pppox)) < 0) {
	error("Failed to connect PPPoE socket: %d %m", errno);
	return -1;
    }

    return conn->sessionSocket;
}
Beispiel #8
0
/* Unfortunately this hook only allows direct access to choose
 * a remote address but we also want to obtain local addresses 
 * from address pools. We need direct access into ipcp_wantoptions[]
 * as a workaround. See call to hook in ipcp.c.
 */
static void ippool_choose_ip(u_int32_t *hisaddr)
{
	ipcp_options *wo = &ipcp_wantoptions[0];
	ipcp_options *go = &ipcp_gotoptions[0];
	ipcp_options *ao = &ipcp_allowoptions[0];
	ipcp_options *ho = &ipcp_hisoptions[0];
	CLIENT *cl;
	int result = 0;

	cl = clnt_create(ippool_server, IPPOOL_PROG, IPPOOL_VERSION, "udp");
	if (cl == NULL) {
		fatal("ippool: %s", clnt_spcreateerror(ippool_server));
	}

	/* Allocate local and remote IP addresses unless they're
	 * already specified.  In the local address case, this only
	 * works when the "noipdefault" option is specified to prevent
	 * pppd from trying to use a default IP address.
	 */
	if (wo->ouraddr == 0) {
		result = ippool_addr_alloc(cl, ippool_pool_name2 ? ippool_pool_name2 : ippool_pool_name, &ippool_addr[1].s_addr);
		if (result < 0) {
			goto out;
		}

		/* We must mess with internal ipcp data here. Another
		 * result parameter like hisaddr would be much
		 * cleaner.
		 */
		wo->ouraddr = ippool_addr[1].s_addr;
		wo->accept_local = 0;
		go->ouraddr = ippool_addr[1].s_addr;
		go->accept_local = 0;
	} else {
		if (ippool_debug) {
			info("Using explicit local address %s", ip_ntoa(go->ouraddr));
		}
	}

	/* Use address from earlier hook if assigned. */
	if (old_ip_choose_hook) {
		old_ip_choose_hook(hisaddr);
		if (*hisaddr) {
			script_setenv("IPPOOL_ALLOCATED_ADDRESS", "FALSE", 0);
			script_setenv("RADIUS_ALLOCATED_ADDRESS", "TRUE", 0);
			goto out;
		}
	}

	if (wo->hisaddr == 0) {
		result = ippool_addr_alloc(cl, ippool_pool_name, &ippool_addr[0].s_addr);
		if (result < 0) {
			goto out;
		}
		*hisaddr = ippool_addr[0].s_addr;
		script_setenv("IPPOOL_ALLOCATED_ADDRESS", "TRUE", 0);
		script_setenv("RADIUS_ALLOCATED_ADDRESS", "FALSE", 0);
	} else {
		script_setenv("IPPOOL_ALLOCATED_ADDRESS", "FALSE", 0);
		script_setenv("RADIUS_ALLOCATED_ADDRESS", "FALSE", 0);
		if (ippool_debug) {
			info("Using explicit remote address %s", ip_ntoa(go->hisaddr));
		}
	}

out:
	if (result < 0) {
		if (ippool_addr[0].s_addr != 0) {
			ippool_addr_free(cl, ippool_pool_name, ippool_addr[0].s_addr);
			ippool_addr[0].s_addr = 0;
		}
		if (ippool_addr[1].s_addr != 0) {
			ippool_addr_free(cl, ippool_pool_name2 ? ippool_pool_name2 : ippool_pool_name, ippool_addr[1].s_addr);
			ippool_addr[1].s_addr = 0;
		}
	}

	clnt_destroy(cl);
}
Beispiel #9
0
static int std_rcv_pado(struct session* ses,
			struct pppoe_packet *p_in,
			struct pppoe_packet **p_out){

    struct pppoe_tag *ac_name, *srv_name;
    char ac[1024], srv[1024];
    
    if(ses->state != PADO_CODE ){
	poe_error(ses,"Unexpected packet: %P",p_in);
	return 0;
    }
    
    if( verify_packet(ses, p_in) < 0)
	return 0;
    
    if (DEB_DISC2)
	poe_dbglog (ses,"PADO received: %P", p_in);
    
    memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll));
    memcpy(&ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll));
    
    ses->curr_pkt.hdr->code = PADR_CODE;
    
    /* The HOST_UNIQ has been verified already... there's no "if" about this */
    /* if(ses->filt->htag) */
    copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_HOST_UNIQ));	
    
    if (ses->filt->ntag) {
    	ses->curr_pkt.tags[TAG_AC_NAME]=NULL;
    }
    
    ac_name = get_tag(p_in->hdr,PTT_AC_NAME);
    srv_name = get_tag(p_in->hdr,PTT_SRV_NAME);

    memset(ac, 0, sizeof(ac)); 	 
    memset(srv, 0, sizeof(srv)); 	 
    
    strncpy(ac, ac_name->tag_data, ntohs(ac_name->tag_len));
    strncpy(srv, srv_name->tag_data, ntohs(srv_name->tag_len));

    script_setenv("AC_NAME", ac, 1);
    script_setenv("SRV_NAME", srv, 1);
    
    if(ses->filt->stag) {
    	ses->curr_pkt.tags[TAG_SRV_NAME]=NULL;
    }
    copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_SRV_NAME));
    
    copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_COOKIE));
    copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_RELAY_SID));
    
    ses->state = PADS_CODE;
    
    ses->retransmits = 0;
    
    send_disc(ses, &ses->curr_pkt);
    (*p_out) = &ses->curr_pkt;
    
    if (DEB_DISC)
	poe_dbglog (ses,"Sent PADR: %P", *p_out);

    if (ses->np)
	return 1;
    
    return 0;
}
Beispiel #10
0
/**********************************************************************
 * %FUNCTION: PPPOEConnectDevice
 * %ARGUMENTS:
 * None
 * %RETURNS:
 * Non-negative if all goes well; -1 otherwise
 * %DESCRIPTION:
 * Connects PPPoE device.
 ***********************************************************************/
static int
PPPOEConnectDevice(void)
{
    struct sockaddr_pppox sp;
    static int qosidx=6410;

    strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
    if (existingSession) {
	unsigned int mac[ETH_ALEN];
	int i, ses;
	if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
		   &ses, &mac[0], &mac[1], &mac[2],
		   &mac[3], &mac[4], &mac[5]) != 7) {
	    fatal("Illegal value for rp_pppoe_sess option");
	}
	conn->session = htons(ses);
	for (i=0; i<ETH_ALEN; i++) {
	    conn->peerEth[i] = (unsigned char) mac[i];
	}
    } else {
	discovery(conn);
	if (conn->discoveryState != STATE_SESSION) {
	    error("Unable to complete PPPoE Discovery");
	    return -1;
	}
    }

    /* Set PPPoE session-number for further consumption */
    ppp_session_number = ntohs(conn->session);

    /* Make the session socket */
    conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
    if (conn->sessionSocket < 0) {
	error("Failed to create PPPoE socket: %m");
	goto errout;
    }
    sp.sa_family = AF_PPPOX;
    sp.sa_protocol = PX_PROTO_OE;
    sp.sa_addr.pppoe.sid = conn->session;
    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);

    /* Set remote_number for ServPoET */
    sprintf(remote_number, "%02X:%02X:%02X:%02X:%02X:%02X",
	    (unsigned) conn->peerEth[0],
	    (unsigned) conn->peerEth[1],
	    (unsigned) conn->peerEth[2],
	    (unsigned) conn->peerEth[3],
	    (unsigned) conn->peerEth[4],
	    (unsigned) conn->peerEth[5]);
    warn("Connected to %02X:%02X:%02X:%02X:%02X:%02X via interface %s",
	 (unsigned) conn->peerEth[0],
	 (unsigned) conn->peerEth[1],
	 (unsigned) conn->peerEth[2],
	 (unsigned) conn->peerEth[3],
	 (unsigned) conn->peerEth[4],
	 (unsigned) conn->peerEth[5],
	 conn->ifName);

    script_setenv("MACREMOTE", remote_number, 0);

    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
		sizeof(struct sockaddr_pppox)) < 0) {
	fatal("Failed to connect PPPoE socket: %d %m", errno);
	close(conn->sessionSocket);
	goto errout;
    }
#ifdef HAVE_AQOS
    if (bandwidthup!=0 && bandwidthdown!=0)
	{
	char uplevel[64];
	char downlevel[64];
	char mac[64];
	sprintf(mac, MACSTR, MAC2STR(conn->myEth));
	sprintf(uplevel,"%d",bandwidthup/1000);
	sprintf(downlevel,"%d",bandwidthdown/1000);
	fprintf(stderr,"use bandwidth down value to %d\n",bandwidthdown);
	fprintf(stderr,"use bandwidth up value to %d\n",bandwidthdown);
	int ret = addrule(mac,uplevel,downlevel);
		    if (!ret)
			{
			qosidx+=10;
			if (qosidx>8190)
			    qosidx=0;
			add_usermac(mac, qosidx, uplevel,downlevel,"0" );
			}else if (ret>1)
			{
			system("startstop_f wshaper");
			}	    
	}
#endif
    return conn->sessionSocket;

 errout:
    if (conn->discoverySocket >= 0) {
	sendPADT(conn, NULL);
	close(conn->discoverySocket);
	conn->discoverySocket = -1;
    }
    return -1;

}
Beispiel #11
0
static int process_split_xxclude(struct openconnect_info *vpninfo,
				 int include, const char *route, int *v4_incs,
				 int *v6_incs)
{
	struct in_addr addr;
	const char *in_ex = include ? "IN" : "EX";
	char envname[80];
	char *slash, *endp;
	int masklen;

	slash = strchr(route, '/');
	if (!slash) {
	badinc:
		if (include)
			vpn_progress(vpninfo, PRG_ERR,
				     _("Discard bad split include: \"%s\"\n"),
				     route);
		else
			vpn_progress(vpninfo, PRG_ERR,
				     _("Discard bad split exclude: \"%s\"\n"),
				     route);
		return -EINVAL;
	}

	*slash = 0;

	if (strchr(route, ':')) {
		snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_ADDR", in_ex,
			 *v6_incs);
		script_setenv(vpninfo, envname, route, 0);

		snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_MASKLEN", in_ex,
			 *v6_incs);
		script_setenv(vpninfo, envname, slash+1, 0);

		(*v6_incs)++;
		return 0;
	}

	if (!inet_aton(route, &addr)) {
		*slash = '/';
		goto badinc;
	}

	envname[79] = 0;
	snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_ADDR", in_ex, *v4_incs);
	script_setenv(vpninfo, envname, route, 0);

	/* Put it back how we found it */
	*slash = '/';

	if ((masklen = strtol(slash+1, &endp, 10))<=32 && *endp!='.') {
		/* mask is /N */
		addr.s_addr = netmaskbits(masklen);
	} else if (inet_aton(slash+1, &addr)) {
		/* mask is /A.B.C.D */
		masklen = netmasklen(addr);
	} else {
		goto badinc;
	}

	snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASK", in_ex, *v4_incs);
	script_setenv(vpninfo, envname, inet_ntoa(addr), 0);

	snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASKLEN", in_ex, *v4_incs);
	script_setenv_int(vpninfo, envname, masklen);

	(*v4_incs)++;
	return 0;
}
Beispiel #12
0
int script_setenv_int(struct openconnect_info *vpninfo, const char *opt, int value)
{
	char buf[16];
	sprintf(buf, "%d", value);
	return script_setenv(vpninfo, opt, buf, 0);
}
Beispiel #13
0
int script_config_tun(struct openconnect_info *vpninfo, const char *reason)
{
	wchar_t *script_w;
	wchar_t *script_env;
	int nr_chars;
	int ret;
	char *cmd;
	PROCESS_INFORMATION pi;
	STARTUPINFOW si;
	DWORD cpflags;

	if (!vpninfo->vpnc_script || vpninfo->script_tun)
		return 0;

	memset(&si, 0, sizeof(si));
	si.cb = sizeof(si);
	/* probably superfluous */
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;

	script_setenv(vpninfo, "reason", reason, 0);

	if (asprintf(&cmd, "cscript.exe \"%s\"", vpninfo->vpnc_script) == -1)
		return 0;

	nr_chars = MultiByteToWideChar(CP_UTF8, 0, cmd, -1, NULL, 0);
	script_w = malloc(nr_chars * sizeof(wchar_t));

	if (!script_w) {
		free(cmd);
		return -ENOMEM;
	}

	MultiByteToWideChar(CP_UTF8, 0, cmd, -1, script_w, nr_chars);

	free(cmd);

	script_env = create_script_env(vpninfo);

	cpflags = CREATE_UNICODE_ENVIRONMENT;
	/* If we're running from a console, let the script use it too. */
	if (!GetConsoleWindow())
		cpflags |= CREATE_NO_WINDOW;

	if (CreateProcessW(NULL, script_w, NULL, NULL, FALSE, cpflags,
			   script_env, NULL, &si, &pi)) {
		ret = WaitForSingleObject(pi.hProcess,10000);
		CloseHandle(pi.hThread);
		CloseHandle(pi.hProcess);
		if (ret == WAIT_TIMEOUT)
			ret = -ETIMEDOUT;
		else
			ret = 0;
	} else {
		ret = -EIO;
	}

	free(script_env);

	if (ret < 0) {
		char *errstr = openconnect__win32_strerror(GetLastError());
		vpn_progress(vpninfo, PRG_ERR,
			     _("Failed to spawn script '%s' for %s: %s\n"),
			     vpninfo->vpnc_script, reason, errstr);
		free(errstr);
		goto cleanup;
	}

 cleanup:
	free(script_w);
	return ret;
}
Beispiel #14
0
void prepare_script_env(struct openconnect_info *vpninfo)
{
	if (vpninfo->ip_info.gateway_addr)
		script_setenv(vpninfo, "VPNGATEWAY", vpninfo->ip_info.gateway_addr, 0);

	set_banner(vpninfo);
	script_setenv(vpninfo, "CISCO_SPLIT_INC", NULL, 0);
	script_setenv(vpninfo, "CISCO_SPLIT_EXC", NULL, 0);

	script_setenv_int(vpninfo, "INTERNAL_IP4_MTU", vpninfo->ip_info.mtu);

	if (vpninfo->ip_info.addr) {
		script_setenv(vpninfo, "INTERNAL_IP4_ADDRESS", vpninfo->ip_info.addr, 0);
		if (vpninfo->ip_info.netmask) {
			struct in_addr addr;
			struct in_addr mask;

			if (inet_aton(vpninfo->ip_info.addr, &addr) &&
			    inet_aton(vpninfo->ip_info.netmask, &mask)) {
				char *netaddr;

				addr.s_addr &= mask.s_addr;
				netaddr = inet_ntoa(addr);

				script_setenv(vpninfo, "INTERNAL_IP4_NETADDR", netaddr, 0);
				script_setenv(vpninfo, "INTERNAL_IP4_NETMASK", vpninfo->ip_info.netmask, 0);
				script_setenv_int(vpninfo, "INTERNAL_IP4_NETMASKLEN", netmasklen(mask));
			}
		}
	}
	if (vpninfo->ip_info.addr6) {
		script_setenv(vpninfo, "INTERNAL_IP6_ADDRESS", vpninfo->ip_info.addr6, 0);
		script_setenv(vpninfo, "INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 0);
	} else if (vpninfo->ip_info.netmask6) {
               char *slash = strchr(vpninfo->ip_info.netmask6, '/');
               script_setenv(vpninfo, "INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 0);
               if (slash) {
                       *slash = 0;
                       script_setenv(vpninfo, "INTERNAL_IP6_ADDRESS", vpninfo->ip_info.netmask6, 0);
                       *slash = '/';
               }
	}

	if (vpninfo->ip_info.dns[0])
		script_setenv(vpninfo, "INTERNAL_IP4_DNS", vpninfo->ip_info.dns[0], 0);
	else
		script_setenv(vpninfo, "INTERNAL_IP4_DNS", NULL, 0);
	if (vpninfo->ip_info.dns[1])
		script_setenv(vpninfo, "INTERNAL_IP4_DNS", vpninfo->ip_info.dns[1], 1);
	if (vpninfo->ip_info.dns[2])
		script_setenv(vpninfo, "INTERNAL_IP4_DNS", vpninfo->ip_info.dns[2], 1);

	if (vpninfo->ip_info.nbns[0])
		script_setenv(vpninfo, "INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[0], 0);
	else
		script_setenv(vpninfo, "INTERNAL_IP4_NBNS", NULL, 0);
	if (vpninfo->ip_info.nbns[1])
		script_setenv(vpninfo, "INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[1], 1);
	if (vpninfo->ip_info.nbns[2])
		script_setenv(vpninfo, "INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[2], 1);

	if (vpninfo->ip_info.domain)
		script_setenv(vpninfo, "CISCO_DEF_DOMAIN", vpninfo->ip_info.domain, 0);
	else
		script_setenv(vpninfo, "CISCO_DEF_DOMAIN", NULL, 0);

	if (vpninfo->ip_info.proxy_pac)
		script_setenv(vpninfo, "CISCO_PROXY_PAC", vpninfo->ip_info.proxy_pac, 0);

	if (vpninfo->ip_info.split_dns) {
		char *list;
		int len = 0;
		struct oc_split_include *dns = vpninfo->ip_info.split_dns;

		while (dns) {
			len += strlen(dns->route) + 1;
			dns = dns->next;
		}
		list = malloc(len);
		if (list) {
			char *p = list;

			dns = vpninfo->ip_info.split_dns;
			while (1) {
				strcpy(p, dns->route);
				p += strlen(p);
				dns = dns->next;
				if (!dns)
					break;
				*(p++) = ',';
			}
			script_setenv(vpninfo, "CISCO_SPLIT_DNS", list, 0);
			free(list);
		}
	}
	if (vpninfo->ip_info.split_includes) {
		struct oc_split_include *this = vpninfo->ip_info.split_includes;
		int nr_split_includes = 0;
		int nr_v6_split_includes = 0;

		while (this) {
			process_split_xxclude(vpninfo, 1, this->route,
					      &nr_split_includes,
					      &nr_v6_split_includes);
			this = this->next;
		}
		if (nr_split_includes)
			script_setenv_int(vpninfo, "CISCO_SPLIT_INC", nr_split_includes);
		if (nr_v6_split_includes)
			script_setenv_int(vpninfo, "CISCO_IPV6_SPLIT_INC", nr_v6_split_includes);
	}
	if (vpninfo->ip_info.split_excludes) {
		struct oc_split_include *this = vpninfo->ip_info.split_excludes;
		int nr_split_excludes = 0;
		int nr_v6_split_excludes = 0;

		while (this) {
			process_split_xxclude(vpninfo, 0, this->route,
					      &nr_split_excludes,
					      &nr_v6_split_excludes);
			this = this->next;
		}
		if (nr_split_excludes)
			script_setenv_int(vpninfo, "CISCO_SPLIT_EXC", nr_split_excludes);
		if (nr_v6_split_excludes)
			script_setenv_int(vpninfo, "CISCO_IPV6_SPLIT_EXC", nr_v6_split_excludes);
	}
	setenv_cstp_opts(vpninfo);
}
Beispiel #15
0
/**********************************************************************
 * %FUNCTION: PPPOEConnectDevice
 * %ARGUMENTS:
 * None
 * %RETURNS:
 * Non-negative if all goes well; -1 otherwise
 * %DESCRIPTION:
 * Connects PPPoE device.
 ***********************************************************************/
static int
PPPOEConnectDevice(void)
{
    struct sockaddr_pppox sp;
    struct ifreq ifr;
    int s;

    /* Restore configuration */
    lcp_allowoptions[0].mru = conn->mtu;
    lcp_wantoptions[0].mru = conn->mru;

    /* Update maximum MRU */
    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) {
	error("Can't get MTU for %s: %m", conn->ifName);
	return -1;
    }
    strncpy(ifr.ifr_name, conn->ifName, sizeof(ifr.ifr_name));
    if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
	error("Can't get MTU for %s: %m", conn->ifName);
	close(s);
	return -1;
    }
    close(s);

    if (lcp_allowoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD) {
	lcp_allowoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
    }
    if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD) {
	lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
    }

    /* Open session socket before discovery phase, to avoid losing session */
    /* packets sent by peer just after PADS packet (noted on some Cisco    */
    /* server equipment).                                                  */
    /* Opening this socket just before waitForPADS in the discovery()      */
    /* function would be more appropriate, but it would mess-up the code   */
    conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
    if (conn->sessionSocket < 0) {
	error("Failed to create PPPoE socket: %m");
	return -1;
    }

    if (acName) {
	SET_STRING(conn->acName, acName);
    }
    if (pppd_pppoe_service) {
	SET_STRING(conn->serviceName, pppd_pppoe_service);
    }

    strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
    if (existingSession) {
	unsigned int mac[ETH_ALEN];
	int i, ses;
	if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
		   &ses, &mac[0], &mac[1], &mac[2],
		   &mac[3], &mac[4], &mac[5]) != 7) {
	    fatal("Illegal value for rp_pppoe_sess option");
	}
	conn->session = htons(ses);
	for (i=0; i<ETH_ALEN; i++) {
	    conn->peerEth[i] = (unsigned char) mac[i];
	}
    } else {
        conn->discoverySocket =
            openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth, NULL);
        discovery(conn);
	if (conn->discoveryState != STATE_SESSION) {
	    error("Unable to complete PPPoE Discovery");
	    goto ERROR;
	}
    }

    /* Set PPPoE session-number for further consumption */
    ppp_session_number = ntohs(conn->session);

    sp.sa_family = AF_PPPOX;
    sp.sa_protocol = PX_PROTO_OE;
    sp.sa_addr.pppoe.sid = conn->session;
    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);

    /* Set remote_number for ServPoET */
    sprintf(remote_number, "%02X:%02X:%02X:%02X:%02X:%02X",
	    (unsigned) conn->peerEth[0],
	    (unsigned) conn->peerEth[1],
	    (unsigned) conn->peerEth[2],
	    (unsigned) conn->peerEth[3],
	    (unsigned) conn->peerEth[4],
	    (unsigned) conn->peerEth[5]);

    warn("Connected to %02X:%02X:%02X:%02X:%02X:%02X via interface %s",
	 (unsigned) conn->peerEth[0],
	 (unsigned) conn->peerEth[1],
	 (unsigned) conn->peerEth[2],
	 (unsigned) conn->peerEth[3],
	 (unsigned) conn->peerEth[4],
	 (unsigned) conn->peerEth[5],
	 conn->ifName);

    script_setenv("MACREMOTE", remote_number, 0);

    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
		sizeof(struct sockaddr_pppox)) < 0) {
	error("Failed to connect PPPoE socket: %d %m", errno);
	goto ERROR;
    }

    return conn->sessionSocket;

 ERROR:
    close(conn->sessionSocket);
    conn->sessionSocket = -1;
    /* Send PADT to reset the session unresponsive at buggy nas */
    sendPADT(conn, NULL);
    if (!existingSession) {
	close(conn->discoverySocket);
	conn->discoverySocket = -1;
    }
    return -1;
}
/*
 * Make a new bundle or join us to an existing bundle
 * if we are doing multilink.
 */
int
mp_join_bundle()
{
	lcp_options *go = &lcp_gotoptions[0];
	lcp_options *ho = &lcp_hisoptions[0];
	lcp_options *ao = &lcp_allowoptions[0];
	int unit, pppd_pid;
	int l, mtu;
	char *p;
	TDB_DATA key, pid, rec;

	if (doing_multilink) {
		/* have previously joined a bundle */
		if (!go->neg_mrru || !ho->neg_mrru) {
			notice("oops, didn't get multilink on renegotiation");
			lcp_close(pcb, "multilink required");
			return 0;
		}
		/* XXX should check the peer_authname and ho->endpoint
		   are the same as previously */
		return 0;
	}

	if (!go->neg_mrru || !ho->neg_mrru) {
		/* not doing multilink */
		if (go->neg_mrru)
			notice("oops, multilink negotiated only for receive");
		mtu = ho->neg_mru? ho->mru: PPP_MRU;
		if (mtu > ao->mru)
			mtu = ao->mru;
		if (demand) {
			/* already have a bundle */
			cfg_bundle(0, 0, 0, 0);
			netif_set_mtu(pcb, mtu);
			return 0;
		}
		make_new_bundle(0, 0, 0, 0);
		set_ifunit(1);
		netif_set_mtu(pcb, mtu);
		return 0;
	}

	doing_multilink = 1;

	/*
	 * Find the appropriate bundle or join a new one.
	 * First we make up a name for the bundle.
	 * The length estimate is worst-case assuming every
	 * character has to be quoted.
	 */
	l = 4 * strlen(peer_authname) + 10;
	if (ho->neg_endpoint)
		l += 3 * ho->endpoint.length + 8;
	if (bundle_name)
		l += 3 * strlen(bundle_name) + 2;
	bundle_id = malloc(l);
	if (bundle_id == 0)
		novm("bundle identifier");

	p = bundle_id;
	p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
	if (ho->neg_endpoint || bundle_name)
		*p++ = '/';
	if (ho->neg_endpoint)
		p += slprintf(p, bundle_id+l-p, "%s",
			      epdisc_to_str(&ho->endpoint));
	if (bundle_name)
		p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);

	/* Make the key for the list of links belonging to the bundle */
	l = p - bundle_id;
	blinks_id = malloc(l + 7);
	if (blinks_id == NULL)
		novm("bundle links key");
	slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7);

	/*
	 * For demand mode, we only need to configure the bundle
	 * and attach the link.
	 */
	mtu = LWIP_MIN(ho->mrru, ao->mru);
	if (demand) {
		cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
		netif_set_mtu(pcb, mtu);
		script_setenv("BUNDLE", bundle_id + 7, 1);
		return 0;
	}

	/*
	 * Check if the bundle ID is already in the database.
	 */
	unit = -1;
	lock_db();
	key.dptr = bundle_id;
	key.dsize = p - bundle_id;
	pid = tdb_fetch(pppdb, key);
	if (pid.dptr != NULL) {
		/* bundle ID exists, see if the pppd record exists */
		rec = tdb_fetch(pppdb, pid);
		if (rec.dptr != NULL && rec.dsize > 0) {
			/* make sure the string is null-terminated */
			rec.dptr[rec.dsize-1] = 0;
			/* parse the interface number */
			parse_num(rec.dptr, "IFNAME=ppp", &unit);
			/* check the pid value */
			if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
			    || !process_exists(pppd_pid)
			    || !owns_unit(pid, unit))
				unit = -1;
			free(rec.dptr);
		}
		free(pid.dptr);
	}

	if (unit >= 0) {
		/* attach to existing unit */
		if (bundle_attach(unit)) {
			set_ifunit(0);
			script_setenv("BUNDLE", bundle_id + 7, 0);
			make_bundle_links(1);
			unlock_db();
			info("Link attached to %s", ifname);
			return 1;
		}
		/* attach failed because bundle doesn't exist */
	}

	/* we have to make a new bundle */
	make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
	set_ifunit(1);
	netif_set_mtu(pcb, mtu);
	script_setenv("BUNDLE", bundle_id + 7, 1);
	make_bundle_links(pcb);
	unlock_db();
	info("New bundle %s created", ifname);
	multilink_master = 1;
	return 0;
}
Beispiel #17
0
/**********************************************************************
 * %FUNCTION: PPPOEConnectDevice
 * %ARGUMENTS:
 * None
 * %RETURNS:
 * Non-negative if all goes well; -1 otherwise
 * %DESCRIPTION:
 * Connects PPPoE device.
 ***********************************************************************/
static int
PPPOEConnectDevice(void)
{
    struct sockaddr_pppox sp;

    /* Open session socket before discovery phase, to avoid losing session */
    /* packets sent by peer just after PADS packet (noted on some Cisco    */
    /* server equipment).                                                  */
    /* Opening this socket just before waitForPADS in the discovery()      */
    /* function would be more appropriate, but it would mess-up the code   */
    conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
    if (conn->sessionSocket < 0) {
	error("Failed to create PPPoE socket: %m");
	return -1;
    }

    strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
    if (existingSession) {
	unsigned int mac[ETH_ALEN];
	int i, ses;
	if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
		   &ses, &mac[0], &mac[1], &mac[2],
		   &mac[3], &mac[4], &mac[5]) != 7) {
	    fatal("Illegal value for rp_pppoe_sess option");
	}
	conn->session = htons(ses);
	for (i=0; i<ETH_ALEN; i++) {
	    conn->peerEth[i] = (unsigned char) mac[i];
	}
    } else {
        conn->discoverySocket =
            openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
        discovery(conn);
	if (conn->discoveryState != STATE_SESSION) {
	    error("Unable to complete PPPoE Discovery");
	    return -1;
	}
    }

    /* Set PPPoE session-number for further consumption */
    ppp_session_number = ntohs(conn->session);

    sp.sa_family = AF_PPPOX;
    sp.sa_protocol = PX_PROTO_OE;
    sp.sa_addr.pppoe.sid = conn->session;
    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);

    /* Set remote_number for ServPoET */
    sprintf(remote_number, "%02X:%02X:%02X:%02X:%02X:%02X",
	    (unsigned) conn->peerEth[0],
	    (unsigned) conn->peerEth[1],
	    (unsigned) conn->peerEth[2],
	    (unsigned) conn->peerEth[3],
	    (unsigned) conn->peerEth[4],
	    (unsigned) conn->peerEth[5]);

    warn("Connected to %02X:%02X:%02X:%02X:%02X:%02X via interface %s",
	 (unsigned) conn->peerEth[0],
	 (unsigned) conn->peerEth[1],
	 (unsigned) conn->peerEth[2],
	 (unsigned) conn->peerEth[3],
	 (unsigned) conn->peerEth[4],
	 (unsigned) conn->peerEth[5],
	 conn->ifName);

    script_setenv("MACREMOTE", remote_number, 0);

    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
		sizeof(struct sockaddr_pppox)) < 0) {
	error("Failed to connect PPPoE socket: %d %m", errno);
	return -1;
    }

    return conn->sessionSocket;
}