Example #1
0
static int
pptpd_listener_start(pptpd_listener *_this)
{
	int sock, ival, sock_gre;
	struct sockaddr_in bind_sin, bind_sin_gre;
	int wildcardbinding;
#ifdef NPPPD_FAKEBIND
	extern void set_faith(int, int);
#endif

	wildcardbinding =
	    (_this->bind_sin.sin_addr.s_addr == INADDR_ANY)?  1 : 0;
	sock = -1;
	sock_gre = -1;
	memcpy(&bind_sin, &_this->bind_sin, sizeof(bind_sin));
	memcpy(&bind_sin_gre, &_this->bind_sin_gre, sizeof(bind_sin_gre));

	if (_this->phy_label[0] == '\0')
		strlcpy(_this->phy_label, PPTPD_DEFAULT_LAYER2_LABEL,
		    sizeof(_this->phy_label));
	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		pptpd_log(_this->self, LOG_ERR, "socket() failed at %s(): %m",
		    __func__);
		goto fail;
	}
	ival = 1;
	if(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &ival, sizeof(ival)) < 0){
		pptpd_log(_this->self, LOG_WARNING,
		    "setsockopt(SO_REUSEPORT) failed at %s(): %m", __func__);
	}
#ifdef NPPPD_FAKEBIND
	if (!wildcardbinding)
		set_faith(sock, 1);
#endif
#if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF)
	ival = 1;
	if (setsockopt(sock, IPPROTO_IP, IP_STRICT_RCVIF, &ival, sizeof(ival))
	    != 0)
		pptpd_log(_this->self, LOG_WARNING,
		    "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__);
#endif
	if ((ival = fcntl(sock, F_GETFL, 0)) < 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "fcntl(F_GET_FL) failed at %s(): %m", __func__);
		goto fail;
	} else if (fcntl(sock, F_SETFL, ival | O_NONBLOCK) < 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "fcntl(F_SET_FL) failed at %s(): %m", __func__);
		goto fail;
	}
	if (bind(sock, (struct sockaddr *)&_this->bind_sin,
	    _this->bind_sin.sin_len) != 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "bind(%s:%u) failed at %s(): %m",
		    inet_ntoa(_this->bind_sin.sin_addr),
		    ntohs(_this->bind_sin.sin_port), __func__);
		goto fail;
	}
	if (listen(sock, PPTP_BACKLOG) != 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "listen(%s:%u) failed at %s(): %m",
		    inet_ntoa(_this->bind_sin.sin_addr),
		    ntohs(_this->bind_sin.sin_port), __func__);
		goto fail;
	}
#ifdef NPPPD_FAKEBIND
	if (!wildcardbinding)
		set_faith(sock, 0);
#endif
	pptpd_log(_this->self, LOG_INFO, "Listening %s:%u/tcp (PPTP PAC) [%s]",
	    inet_ntoa(_this->bind_sin.sin_addr),
	    ntohs(_this->bind_sin.sin_port), _this->phy_label);

	/* GRE */
	bind_sin_gre.sin_port = 0;
	if ((sock_gre = priv_socket(AF_INET, SOCK_RAW, IPPROTO_GRE)) < 0) {
		pptpd_log(_this->self, LOG_ERR, "socket() failed at %s(): %m",
		    __func__);
		goto fail;
	}
#ifdef NPPPD_FAKEBIND
	if (!wildcardbinding)
		set_faith(sock_gre, 1);
#endif
#if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF)
	ival = 1;
	if (setsockopt(sock_gre, IPPROTO_IP, IP_STRICT_RCVIF, &ival,
	    sizeof(ival)) != 0)
		pptpd_log(_this->self, LOG_WARNING,
		    "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__);
#endif
#ifdef IP_PIPEX
	ival = 1;
	if (setsockopt(sock_gre, IPPROTO_IP, IP_PIPEX, &ival, sizeof(ival))
	    != 0)
		pptpd_log(_this->self, LOG_WARNING,
		    "%s(): setsockopt(IP_PIPEX) failed: %m", __func__);
#endif
	if ((ival = fcntl(sock_gre, F_GETFL, 0)) < 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "fcntl(F_GET_FL) failed at %s(): %m", __func__);
		goto fail;
	} else if (fcntl(sock_gre, F_SETFL, ival | O_NONBLOCK) < 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "fcntl(F_SET_FL) failed at %s(): %m", __func__);
		goto fail;
	}
	if (bind(sock_gre, (struct sockaddr *)&bind_sin_gre,
	    bind_sin_gre.sin_len) != 0) {
		pptpd_log(_this->self, LOG_ERR,
		    "bind(%s:%u) failed at %s(): %m",
		    inet_ntoa(bind_sin_gre.sin_addr),
		    ntohs(bind_sin_gre.sin_port), __func__);
		goto fail;
	}
#ifdef NPPPD_FAKEBIND
	if (!wildcardbinding)
		set_faith(sock_gre, 0);
#endif
	if (wildcardbinding) {
#ifdef USE_LIBSOCKUTIL
		if (setsockoptfromto(sock) != 0) {
			pptpd_log(_this->self, LOG_ERR,
			    "setsockoptfromto() failed in %s(): %m", __func__);
			goto fail;
		}
#else
		/* nothing to do */
#endif
	}
	pptpd_log(_this->self, LOG_INFO, "Listening %s:gre (PPTP PAC)",
	    inet_ntoa(bind_sin_gre.sin_addr));

	_this->sock = sock;
	_this->sock_gre = sock_gre;

	event_set(&_this->ev_sock, _this->sock, EV_READ | EV_PERSIST,
	    pptpd_io_event, _this);
	event_add(&_this->ev_sock, NULL);

	event_set(&_this->ev_sock_gre, _this->sock_gre, EV_READ | EV_PERSIST,
	    pptpd_gre_io_event, _this);
	event_add(&_this->ev_sock_gre, NULL);

	return 0;
fail:
	if (sock >= 0)
		close(sock);
	if (sock_gre >= 0)
		close(sock_gre);

	_this->sock = -1;
	_this->sock_gre = -1;

	return 1;
}
Example #2
0
/* start l2tpd listner */
static int
l2tpd_listener_start(l2tpd_listener *_this)
{
	l2tpd *_l2tpd;
	int    af, lvl, opt, sock, ival;
	char   hbuf[NI_MAXHOST + NI_MAXSERV + 16];

	_l2tpd = _this->self;
	sock = -1;
	af = _this->bind.sin6.sin6_family;
	lvl = (af == AF_INET)? IPPROTO_IP : IPPROTO_IPV6;

	if (_this->tun_name[0] == '\0')
		strlcpy(_this->tun_name, L2TPD_DEFAULT_LAYER2_LABEL,
		    sizeof(_this->tun_name));
	if ((sock = socket(_this->bind.sin6.sin6_family,
	    SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) < 0) {
		l2tpd_log(_l2tpd, LOG_ERR,
		    "socket() failed in %s(): %m", __func__);
		goto fail;
	}
#if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF)
	ival = 1;
	if (setsockopt(sock, IPPROTO_IP, IP_STRICT_RCVIF, &ival, sizeof(ival))
	    != 0)
		l2tpd_log(_l2tpd, LOG_WARNING,
		    "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__);
#endif
	ival = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &ival, sizeof(ival))
	    != 0) {
		l2tpd_log(_l2tpd, LOG_ERR,
		    "setsockopt(,,SO_REUSEPORT) failed in %s(): %m", __func__);
		goto fail;
	}
	if (bind(sock, (struct sockaddr *)&_this->bind,
	    _this->bind.sin6.sin6_len) != 0) {
		l2tpd_log(_l2tpd, LOG_ERR, "Binding %s/udp: %m",
		    addrport_tostring((struct sockaddr *)&_this->bind,
		    _this->bind.sin6.sin6_len, hbuf, sizeof(hbuf)));
		goto fail;
	}
#ifdef USE_LIBSOCKUTIL
	if (setsockoptfromto(sock) != 0) {
		l2tpd_log(_l2tpd, LOG_ERR,
		    "setsockoptfromto() failed in %s(): %m", __func__);
		goto fail;
	}
#else
	opt = (af == AF_INET)? IP_RECVDSTADDR : IPV6_RECVPKTINFO;
	ival = 1;
	if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) {
		l2tpd_log(_l2tpd, LOG_ERR,
		    "setsockopt(,,IP{,V6}_RECVDSTADDR) failed in %s(): %m",
		    __func__);
		goto fail;
	}
#endif
#ifdef USE_SA_COOKIE
	if (af == AF_INET) {
		ival = 1;
		if (setsockopt(sock, IPPROTO_IP, IP_IPSECFLOWINFO, &ival,
		    sizeof(ival)) != 0) {
			l2tpd_log(_l2tpd, LOG_ERR,
			    "setsockopt(,,IP_IPSECFLOWINFO) failed in %s(): %m",
			    __func__);
			goto fail;
		}
	}
#endif
#ifdef IP_PIPEX
	opt = (af == AF_INET)? IP_PIPEX : IPV6_PIPEX;
	ival = 1;
	if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0)
		l2tpd_log(_l2tpd, LOG_WARNING,
		    "%s(): setsockopt(IP{,V6}_PIPEX) failed: %m", __func__);
#endif
	if (_this->conf->require_ipsec) {
#ifdef IP_IPSEC_POLICY
		caddr_t  ipsec_policy_in, ipsec_policy_out;

		opt = (af == AF_INET)? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
		/*
		 * Note: ipsec_set_policy() will assign the buffer for
		 * yacc parser stack, however it never free.
		 * it cause memory leak (-2000byte).
		 */
		if ((ipsec_policy_in = ipsec_set_policy(L2TPD_IPSEC_POLICY_IN,
		    strlen(L2TPD_IPSEC_POLICY_IN))) == NULL) {
			l2tpd_log(_l2tpd, LOG_ERR,
			    "ipsec_set_policy(L2TPD_IPSEC_POLICY_IN) failed "
			    "at %s(): %s: %m", __func__, ipsec_strerror());
		} else if (setsockopt(sock, lvl, opt, ipsec_policy_in,
		    ipsec_get_policylen(ipsec_policy_in)) < 0) {
			l2tpd_log(_l2tpd, LOG_WARNING,
			    "setsockopt(,,IP_IPSEC_POLICY(in)) failed "
			    "in %s(): %m", __func__);
		}
		if ((ipsec_policy_out = ipsec_set_policy(L2TPD_IPSEC_POLICY_OUT,
		    strlen(L2TPD_IPSEC_POLICY_OUT))) == NULL) {
			l2tpd_log(_l2tpd, LOG_ERR,
			    "ipsec_set_policy(L2TPD_IPSEC_POLICY_OUT) failed "
			    "at %s(): %s: %m", __func__, ipsec_strerror());
		}
		if (ipsec_policy_out != NULL &&
		    setsockopt(sock, lvl, opt, ipsec_policy_out,
		    ipsec_get_policylen(ipsec_policy_out)) < 0) {
			l2tpd_log(_l2tpd, LOG_WARNING,
			    "setsockopt(,,IP_IPSEC_POLICY(out)) failed "
			    "in %s(): %m", __func__);
		}
		free(ipsec_policy_in);
		free(ipsec_policy_out);
#elif defined(IP_ESP_TRANS_LEVEL)
		opt = (af == AF_INET)
		    ? IP_ESP_TRANS_LEVEL : IPV6_ESP_TRANS_LEVEL;
		ival = IPSEC_LEVEL_REQUIRE;
		if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) {
			l2tpd_log(_l2tpd, LOG_WARNING,
			    "setsockopt(,,IP{,V6}_ESP_TRANS_LEVEL(out)) failed "
			    "in %s(): %m", __func__);
		}
#else
#error IP_IPSEC_POLICY or IP_ESP_TRANS_LEVEL must be usable.
#endif
	}

	_this->sock = sock;

	event_set(&_this->ev_sock, _this->sock, EV_READ | EV_PERSIST,
	    l2tpd_io_event, _this);
	event_add(&_this->ev_sock, NULL);

	l2tpd_log(_l2tpd, LOG_INFO, "Listening %s/udp (L2TP LNS) [%s]",
	    addrport_tostring((struct sockaddr *)&_this->bind,
	    _this->bind.sin6.sin6_len, hbuf, sizeof(hbuf)), _this->tun_name);

	return 0;
fail:
	if (sock >= 0)
		close(sock);

	return 1;
}