int c_do_connect(struct connection *c, enum c_event ev) { if (c->fd == -1) { log_warnx("connect(%s), lost socket", log_sockaddr(&c->config.TargetAddr)); session_fsm(c->session, SESS_EV_CONN_FAIL, c, 0); return CONN_FREE; } if (c->config.LocalAddr.ss_len != 0) { if (bind(c->fd, (struct sockaddr *)&c->config.LocalAddr, c->config.LocalAddr.ss_len) == -1) { log_warn("bind(%s)", log_sockaddr(&c->config.LocalAddr)); session_fsm(c->session, SESS_EV_CONN_FAIL, c, 0); return CONN_FREE; } } if (connect(c->fd, (struct sockaddr *)&c->config.TargetAddr, c->config.TargetAddr.ss_len) == -1) { if (errno == EINPROGRESS) { event_add(&c->wev, NULL); event_add(&c->ev, NULL); return CONN_XPT_WAIT; } else { log_warn("connect(%s)", log_sockaddr(&c->config.TargetAddr)); session_fsm(c->session, SESS_EV_CONN_FAIL, c, 0); return CONN_FREE; } } event_add(&c->ev, NULL); /* move forward */ return c_do_login(c, CONN_EV_CONNECTED); }
void client_log_error(struct ntp_peer *peer, const char *operation, int error) { const char *address; address = log_sockaddr((struct sockaddr *)&peer->addr->ss); if (peer->lasterror == error) { log_debug("%s %s: %s", operation, address, strerror(error)); return; } peer->lasterror = error; log_warn("%s %s", operation, address); }
int ntp_getmsg(struct sockaddr *sa, char *p, ssize_t len, struct ntp_msg *msg) { if (len != NTP_MSGSIZE_NOAUTH && len != NTP_MSGSIZE) { log_debug("malformed packet received from %s", log_sockaddr(sa)); return (-1); } memcpy(msg, p, sizeof(*msg)); return (0); }
void log_conn_attempt(const struct peer *peer, struct sockaddr *sa) { char *p; const char *b; if (peer == NULL) { /* connection from non-peer, drop */ b = log_sockaddr(sa); logit(LOG_INFO, "connection from non-peer %s refused", b); } else { p = log_fmt_peer(&peer->conf); logit(LOG_INFO, "Connection attempt from %s while session is " "in state %s", p, statenames[peer->state]); free(p); } }
void print_mainconf(struct bgpd_config *conf) { struct in_addr ina; struct listen_addr *la; printf("AS %s", log_as(conf->as)); if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS) printf(" %u", conf->short_as); ina.s_addr = conf->bgpid; printf("\nrouter-id %s\n", inet_ntoa(ina)); printf("socket \"%s\"\n", conf->csock); if (conf->rcsock) printf("socket \"%s\" restricted\n", conf->rcsock); if (conf->holdtime) printf("holdtime %u\n", conf->holdtime); if (conf->min_holdtime) printf("holdtime min %u\n", conf->min_holdtime); if (conf->connectretry) printf("connect-retry %u\n", conf->connectretry); if (conf->flags & BGPD_FLAG_NO_EVALUATE) printf("route-collector yes\n"); if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE) printf("rde route-age evaluate\n"); if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS) printf("rde med compare always\n"); if (conf->log & BGPD_LOG_UPDATES) printf("log updates\n"); TAILQ_FOREACH(la, conf->listen_addrs, entry) printf("listen on %s\n", log_sockaddr((struct sockaddr *)&la->sa)); if (conf->flags & BGPD_FLAG_NEXTHOP_BGP) printf("nexthop qualify via bgp\n"); if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT) printf("nexthop qualify via default\n"); printf("fib-priority %hhu", conf->fib_priority); }
void log_conn_attempt(const struct peer *peer, struct sockaddr *sa) { char *p; const char *b; if (peer == NULL) { /* connection from non-peer, drop */ b = log_sockaddr(sa); logit(LOG_INFO, "connection from non-peer %s refused", b); } else { /* only log if there is a chance that the session may come up */ if (peer->conf.down && peer->state == STATE_IDLE) return; p = log_fmt_peer(&peer->conf); logit(LOG_INFO, "Connection attempt from %s while session is " "in state %s", p, statenames[peer->state]); free(p); } }
void conn_write_dispatch(int fd, short event, void *arg) { struct connection *c = arg; ssize_t n; int error; socklen_t len; if (!(event & EV_WRITE)) { log_debug("spurious write call"); return; } switch (c->state) { case CONN_XPT_WAIT: len = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1 || (errno = error)) { log_warn("connect to %s failed", log_sockaddr(&c->config.TargetAddr)); conn_fsm(c, CONN_EV_FAIL); return; } conn_fsm(c, CONN_EV_CONNECTED); break; default: if ((n = pdu_write(c)) == -1) { log_warn("pdu_write"); conn_fsm(c, CONN_EV_FAIL); return; } if (n == 0) { /* connection closed */ conn_fsm(c, CONN_EV_CLOSED); return; } /* check if there is more to send */ if (pdu_pending(c)) event_add(&c->wev, NULL); } }
int client_dispatch(struct ntp_peer *p, u_int8_t settime) { struct ntp_msg msg; struct msghdr somsg; struct iovec iov[1]; struct timeval tv; char buf[NTP_MSGSIZE]; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(tv))]; } cmsgbuf; struct cmsghdr *cmsg; ssize_t size; double T1, T2, T3, T4; time_t interval; bzero(&somsg, sizeof(somsg)); iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); somsg.msg_iov = iov; somsg.msg_iovlen = 1; somsg.msg_control = cmsgbuf.buf; somsg.msg_controllen = sizeof(cmsgbuf.buf); T4 = getoffset(); if ((size = recvmsg(p->query->fd, &somsg, 0)) == -1) { if (errno == EHOSTUNREACH || errno == EHOSTDOWN || errno == ENETUNREACH || errno == ENETDOWN || errno == ECONNREFUSED || errno == EADDRNOTAVAIL || errno == ENOPROTOOPT || errno == ENOENT) { client_log_error(p, "recvmsg", errno); set_next(p, error_interval()); return (0); } else fatal("recvfrom"); } if (somsg.msg_flags & MSG_TRUNC) { client_log_error(p, "recvmsg packet", EMSGSIZE); set_next(p, error_interval()); return (0); } if (somsg.msg_flags & MSG_CTRUNC) { client_log_error(p, "recvmsg control data", E2BIG); set_next(p, error_interval()); return (0); } #ifdef HAVE_RTABLE if (p->rtable != -1 && setsockopt(p->query->fd, SOL_SOCKET, SO_RTABLE, &p->rtable, sizeof(p->rtable)) == -1) fatal("client_dispatch setsockopt SO_RTABLE"); #endif for (cmsg = CMSG_FIRSTHDR(&somsg); cmsg != NULL; cmsg = CMSG_NXTHDR(&somsg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) { memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); T4 += tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec; break; } } if (T4 < JAN_1970) { client_log_error(p, "recvmsg control format", EBADF); set_next(p, error_interval()); return (0); } ntp_getmsg((struct sockaddr *)&p->addr->ss, buf, size, &msg); if (msg.orgtime.int_partl != p->query->msg.xmttime.int_partl || msg.orgtime.fractionl != p->query->msg.xmttime.fractionl) return (0); if ((msg.status & LI_ALARM) == LI_ALARM || msg.stratum == 0 || msg.stratum > NTP_MAXSTRATUM) { char s[16]; if ((msg.status & LI_ALARM) == LI_ALARM) { strlcpy(s, "alarm", sizeof(s)); } else if (msg.stratum == 0) { /* Kiss-o'-Death (KoD) packet */ strlcpy(s, "KoD", sizeof(s)); } else if (msg.stratum > NTP_MAXSTRATUM) { snprintf(s, sizeof(s), "stratum %d", msg.stratum); } interval = error_interval(); set_next(p, interval); log_info("reply from %s: not synced (%s), next query %llds", log_sockaddr((struct sockaddr *)&p->addr->ss), s, (long long)interval); return (0); } /* * From RFC 2030 (with a correction to the delay math): * * Timestamp Name ID When Generated * ------------------------------------------------------------ * Originate Timestamp T1 time request sent by client * Receive Timestamp T2 time request received by server * Transmit Timestamp T3 time reply sent by server * Destination Timestamp T4 time reply received by client * * The roundtrip delay d and local clock offset t are defined as * * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2. */ T1 = p->query->xmttime; T2 = lfp_to_d(msg.rectime); T3 = lfp_to_d(msg.xmttime); /* * XXX workaround: time_t / tv_sec must never wrap. * around 2020 we will need a solution (64bit time_t / tv_sec). * consider every answer with a timestamp beyond january 2030 bogus. */ if (T2 > JAN_2030 || T3 > JAN_2030) { set_next(p, error_interval()); return (0); } p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2; p->reply[p->shift].delay = (T4 - T1) - (T3 - T2); p->reply[p->shift].status.stratum = msg.stratum; if (p->reply[p->shift].delay < 0) { interval = error_interval(); set_next(p, interval); log_info("reply from %s: negative delay %fs, " "next query %llds", log_sockaddr((struct sockaddr *)&p->addr->ss), p->reply[p->shift].delay, (long long)interval); return (0); } p->reply[p->shift].error = (T2 - T1) - (T3 - T4); p->reply[p->shift].rcvd = getmonotime(); p->reply[p->shift].good = 1; p->reply[p->shift].status.leap = (msg.status & LIMASK); p->reply[p->shift].status.precision = msg.precision; p->reply[p->shift].status.rootdelay = sfp_to_d(msg.rootdelay); p->reply[p->shift].status.rootdispersion = sfp_to_d(msg.dispersion); p->reply[p->shift].status.refid = msg.refid; p->reply[p->shift].status.reftime = lfp_to_d(msg.reftime); p->reply[p->shift].status.poll = msg.ppoll; if (p->addr->ss.ss_family == AF_INET) { p->reply[p->shift].status.send_refid = ((struct sockaddr_in *)&p->addr->ss)->sin_addr.s_addr; } else if (p->addr->ss.ss_family == AF_INET6) { MD5_CTX context; u_int8_t digest[MD5_DIGEST_LENGTH]; MD5_Init(&context); MD5_Update(&context, ((struct sockaddr_in6 *)&p->addr->ss)-> sin6_addr.s6_addr, sizeof(struct in6_addr)); MD5_Final(digest, &context); memcpy((char *)&p->reply[p->shift].status.send_refid, digest, sizeof(u_int32_t)); } else p->reply[p->shift].status.send_refid = msg.xmttime.fractionl; if (p->trustlevel < TRUSTLEVEL_PATHETIC) interval = scale_interval(INTERVAL_QUERY_PATHETIC); else if (p->trustlevel < TRUSTLEVEL_AGGRESSIVE) interval = scale_interval(INTERVAL_QUERY_AGGRESSIVE); else interval = scale_interval(INTERVAL_QUERY_NORMAL); set_next(p, interval); p->state = STATE_REPLY_RECEIVED; /* every received reply which we do not discard increases trust */ if (p->trustlevel < TRUSTLEVEL_MAX) { if (p->trustlevel < TRUSTLEVEL_BADPEER && p->trustlevel + 1 >= TRUSTLEVEL_BADPEER) log_info("peer %s now valid", log_sockaddr((struct sockaddr *)&p->addr->ss)); p->trustlevel++; } log_debug("reply from %s: offset %f delay %f, " "next query %llds %s", log_sockaddr((struct sockaddr *)&p->addr->ss), p->reply[p->shift].offset, p->reply[p->shift].delay, (long long)interval, print_rtable(p->rtable)); client_update(p); if (settime) priv_settime(p->reply[p->shift].offset); if (++p->shift >= OFFSET_ARRAY_SIZE) p->shift = 0; return (0); }
void prepare_listeners(struct bgpd_config *conf) { struct listen_addr *la, *next; int opt = 1; if (TAILQ_EMPTY(conf->listen_addrs)) { if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) fatal("setup_listeners calloc"); la->fd = -1; la->flags = DEFAULT_LISTENER; la->reconf = RECONF_REINIT; la->sa.ss_len = sizeof(struct sockaddr_in); ((struct sockaddr_in *)&la->sa)->sin_family = AF_INET; ((struct sockaddr_in *)&la->sa)->sin_addr.s_addr = htonl(INADDR_ANY); ((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT); TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) fatal("setup_listeners calloc"); la->fd = -1; la->flags = DEFAULT_LISTENER; la->reconf = RECONF_REINIT; la->sa.ss_len = sizeof(struct sockaddr_in6); ((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6; ((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT); TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); } for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) { next = TAILQ_NEXT(la, entry); if (la->reconf != RECONF_REINIT) continue; if ((la->fd = socket(la->sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { if (la->flags & DEFAULT_LISTENER && (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)) { TAILQ_REMOVE(conf->listen_addrs, la, entry); free(la); continue; } else fatal("socket"); } opt = 1; if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) fatal("setsockopt SO_REUSEADDR"); if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) == -1) { switch (la->sa.ss_family) { case AF_INET: log_warn("cannot bind to %s:%u", log_sockaddr((struct sockaddr *)&la->sa), ntohs(((struct sockaddr_in *) &la->sa)->sin_port)); break; case AF_INET6: log_warn("cannot bind to [%s]:%u", log_sockaddr((struct sockaddr *)&la->sa), ntohs(((struct sockaddr_in6 *) &la->sa)->sin6_port)); break; default: log_warn("cannot bind to %s", log_sockaddr((struct sockaddr *)&la->sa)); break; } close(la->fd); TAILQ_REMOVE(conf->listen_addrs, la, entry); free(la); continue; } } }
int main(int argc, char *argv[]) { int c; int debug = 0; int noaction = 0; const char *conffile = CONF_FILE; u_int flags = 0; struct passwd *pw; struct igdpcpd *env; struct in6_addr ssdp_link_nodes = IN6ADDR_LINKLOCAL_SSDP_INIT; struct in6_addr all_nodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; struct ifaddrs *ifap, *ifa, *ifal; struct listen_addr *la; int reuse = 1; unsigned char loop4 = 0; unsigned int loop6 = 0; unsigned char ttl4 = UPNP_MULTICAST_TTL; int ttl6 = UPNP_MULTICAST_TTL; struct ip_mreq mreq4; struct ipv6_mreq mreq6; struct event *ev_sighup; struct event *ev_sigint; struct event *ev_sigterm; struct timeval tv = { 0, 0 }; socklen_t slen; log_init(1); while ((c = getopt(argc, argv, "df:nv")) != -1) { switch (c) { case 'd': debug = 1; break; case 'f': conffile = optarg; break; case 'n': noaction++; break; case 'v': flags |= IGDPCPD_F_VERBOSE; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 0) usage(); if ((env = parse_config(conffile, flags)) == NULL) exit(1); if (noaction) { fprintf(stderr, "configuration ok\n"); exit(0); } if (geteuid()) errx(1, "need root privileges"); if ((pw = getpwnam(IGDPCPD_USER)) == NULL) errx(1, "unknown user %s", IGDPCPD_USER); log_init(debug); if (!debug) { if (daemon(1, 0) == -1) err(1, "failed to daemonize"); } gettimeofday(&env->sc_boottime, NULL); memset(&ssdp4, 0, sizeof(ssdp4)); ssdp4.sin_family = AF_INET; ssdp4.sin_len = sizeof(ssdp4); ssdp4.sin_addr.s_addr = htonl(INADDR_SSDP_GROUP); ssdp4.sin_port = htons(SSDP_PORT); memset(&ssdp6, 0, sizeof(ssdp6)); ssdp6.sin6_family = AF_INET6; ssdp6.sin6_len = sizeof(ssdp6); ssdp6.sin6_addr = ssdp_link_nodes; ssdp6.sin6_port = htons(SSDP_PORT); memset(&pcp4, 0, sizeof(pcp4)); pcp4.sin_family = AF_INET; pcp4.sin_len = sizeof(pcp4); pcp4.sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); pcp4.sin_port = htons(PCP_CLIENT_PORT); memset(&pcp6, 0, sizeof(pcp6)); pcp6.sin6_family = AF_INET6; pcp6.sin6_len = sizeof(pcp6); pcp6.sin6_addr = all_nodes; pcp6.sin6_port = htons(PCP_CLIENT_PORT); if (uname(&name) == -1) fatal("uname"); if (getifaddrs(&ifap) == -1) fatal("getifaddrs"); for (la = TAILQ_FIRST(&env->listen_addrs); la; ) { switch (la->sa.ss_family) { case AF_INET: if (((struct sockaddr_in *)&la->sa)->sin_port == 0) ((struct sockaddr_in *)&la->sa)->sin_port = htons(SSDP_PORT); break; case AF_INET6: if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0) ((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(SSDP_PORT); break; default: fatalx("king bula sez: af borked"); } log_info("listening on %s:%u", log_sockaddr((struct sockaddr *)&la->sa), SSDP_PORT); if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1) fatal("socket"); if (fcntl(la->fd, F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); switch (la->sa.ss_family) { case AF_INET: if (setsockopt(la->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop4, sizeof(loop4)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl4, sizeof(ttl4)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IP, IP_MULTICAST_IF, &(((struct sockaddr_in *)&la->sa)->sin_addr), sizeof(struct in_addr)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IP, IP_RECVDSTADDR, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IP, IP_RECVIF, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); /* Assume AF_LINK always comes first */ for (ifa = ifal = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; switch (ifa->ifa_addr->sa_family) { case AF_LINK: ifal = ifa; break; case AF_INET: if (memcmp(&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, &((struct sockaddr_in *)&la->sa)->sin_addr, sizeof(struct in_addr)) == 0) la->index = ((struct sockaddr_dl *)ifal->ifa_addr)->sdl_index; break; } } break; case AF_INET6: if (setsockopt(la->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop6, sizeof(loop6)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl6, sizeof(ttl6)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &((struct sockaddr_in6 *)&la->sa)->sin6_scope_id, sizeof(((struct sockaddr_in6 *)&la->sa)->sin6_scope_id)) == -1) fatal("setsockopt"); if (setsockopt(la->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); la->index = ((struct sockaddr_in6 *)&la->sa)->sin6_scope_id; break; default: /* NOTREACHED */ break; } if (bind(la->fd, (struct sockaddr *)&la->sa, SA_LEN((struct sockaddr *)&la->sa)) == -1) { struct listen_addr *nla; log_warn("bind on %d failed, skipping", log_sockaddr((struct sockaddr *)&la->sa)); close(la->fd); nla = TAILQ_NEXT(la, entry); TAILQ_REMOVE(&env->listen_addrs, la, entry); free(la); la = nla; continue; } switch (la->sa.ss_family) { case AF_INET: /* Create IPv4 multicast socket if needed */ if (env->sc_mc4_fd == 0) { if ((env->sc_mc4_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) fatal("socket"); if (fcntl(env->sc_mc4_fd, F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); if (setsockopt(env->sc_mc4_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (setsockopt(env->sc_mc4_fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (bind(env->sc_mc4_fd, (struct sockaddr *)&ssdp4, sizeof(ssdp4)) == -1) fatal("bind"); if (setsockopt(env->sc_mc4_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop4, sizeof(loop4)) == -1) fatal("setsockopt"); if (setsockopt(env->sc_mc4_fd, IPPROTO_IP, IP_RECVDSTADDR, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (setsockopt(env->sc_mc4_fd, IPPROTO_IP, IP_RECVIF, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); log_info("listening on %s:%u", log_sockaddr((struct sockaddr *)&ssdp4), SSDP_PORT); } memset(&mreq4, 0, sizeof(mreq4)); mreq4.imr_multiaddr = ssdp4.sin_addr; mreq4.imr_interface = ((struct sockaddr_in *)&la->sa)->sin_addr; if (setsockopt(env->sc_mc4_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq4, sizeof(mreq4)) == -1) fatal("setsockopt"); break; case AF_INET6: /* Create IPv6 multicast socket if needed */ if (env->sc_mc6_fd == 0) { if ((env->sc_mc6_fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) fatal("socket"); if (fcntl(env->sc_mc6_fd, F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); if (setsockopt(env->sc_mc6_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (setsockopt(env->sc_mc6_fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (bind(env->sc_mc6_fd, (struct sockaddr *)&ssdp6, sizeof(ssdp6)) == -1) fatal("bind"); if (setsockopt(env->sc_mc6_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop6, sizeof(loop6)) == -1) fatal("setsockopt"); if (setsockopt(env->sc_mc6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); log_info("listening on %s:%u", log_sockaddr((struct sockaddr *)&ssdp6), SSDP_PORT); } memset(&mreq6, 0, sizeof(mreq6)); mreq6.ipv6mr_multiaddr = ssdp6.sin6_addr; mreq6.ipv6mr_interface = ((struct sockaddr_in6 *)&la->sa)->sin6_scope_id; if (setsockopt(env->sc_mc6_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == -1) fatal("setsockopt"); break; default: /* NOTREACHED */ break; } /* HTTP */ memcpy(&la->http_sa, &la->sa, sizeof(la->sa)); switch (la->http_sa.ss_family) { case AF_INET: ((struct sockaddr_in *)&la->http_sa)->sin_port = htons(env->sc_port); break; case AF_INET6: ((struct sockaddr_in6 *)&la->http_sa)->sin6_port = htons(env->sc_port); break; default: /* NOTREACHED */ break; } if ((la->http_fd = socket(la->http_sa.ss_family, SOCK_STREAM, 0)) == -1) fatal("socket"); if (fcntl(la->http_fd, F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); if (setsockopt(la->http_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) fatal("setsockopt"); if (bind(la->http_fd, (struct sockaddr *)&la->http_sa, SA_LEN((struct sockaddr *)&la->http_sa)) == -1) fatal("bind"); /* If the HTTP port is not explicitly configured, read back * what the kernel gives us so we can use it in SSDP messages */ if (env->sc_port == 0) { slen = sizeof(la->http_fd); if (getsockname(la->http_fd, (struct sockaddr *)&la->http_sa, &slen) == -1) fatal("getsockname"); #if 0 /* Store the port so subsequent HTTP listeners will * attempt to get the same port? */ switch (la->http_sa.ss_family) { case AF_INET: env->sc_port = ntohs(((struct sockaddr_in *)&la->http_sa)->sin_port); break; case AF_INET6: env->sc_port = ntohs(((struct sockaddr_in6 *)&la->http_sa)->sin6_port); break; default: /* NOTREACHED */ break; } #endif } if (listen(la->http_fd, 16) == -1) fatal("listen"); la = TAILQ_NEXT(la, entry); } freeifaddrs(ifap); log_info("startup"); if (chroot(pw->pw_dir) == -1) fatal("chroot"); if (chdir("/") == -1) fatal("chdir(\"/\")"); if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("cannot drop privileges"); if ((env->sc_base = event_base_new()) == NULL) fatalx("event_base_new"); signal(SIGPIPE, SIG_IGN); ev_sighup = evsignal_new(env->sc_base, SIGHUP, handle_signal, env); ev_sigint = evsignal_new(env->sc_base, SIGINT, handle_signal, env); ev_sigterm = evsignal_new(env->sc_base, SIGTERM, handle_signal, env); evsignal_add(ev_sighup, NULL); evsignal_add(ev_sigint, NULL); evsignal_add(ev_sigterm, NULL); if (env->sc_mc4_fd) { env->sc_mc4_ev = event_new(env->sc_base, env->sc_mc4_fd, EV_READ|EV_PERSIST, ssdp_recvmsg, env); event_add(env->sc_mc4_ev, NULL); } if (env->sc_mc6_fd) { env->sc_mc6_ev = event_new(env->sc_base, env->sc_mc6_fd, EV_READ|EV_PERSIST, ssdp_recvmsg, env); event_add(env->sc_mc6_ev, NULL); } env->sc_httpd = evhttp_new(env->sc_base); for (la = TAILQ_FIRST(&env->listen_addrs); la; ) { la->ev = event_new(env->sc_base, la->fd, EV_READ|EV_PERSIST, ssdp_recvmsg, env); event_add(la->ev, NULL); evhttp_accept_socket(env->sc_httpd, la->http_fd); la = TAILQ_NEXT(la, entry); } env->sc_root = upnp_root_device(env->sc_version, UPNP_DEVICE_INTERNET_GATEWAY_DEVICE, env->sc_httpd); /* FIXME DEBUG */ evhttp_set_gencb(env->sc_httpd, upnp_debug, env); env->sc_announce_ev = evtimer_new(env->sc_base, ssdp_announce, env); evtimer_add(env->sc_announce_ev, &tv); event_base_dispatch(env->sc_base); return (0); }