static void test_extra_filter(const struct test_params p) { struct sockaddr * const addr = new_any_sockaddr(p.recv_family, p.recv_port); int fd1, fd2, opt; fprintf(stderr, "Testing too many filters...\n"); fd1 = socket(p.recv_family, p.protocol, 0); if (fd1 < 0) error(1, errno, "failed to create socket 1"); fd2 = socket(p.recv_family, p.protocol, 0); if (fd2 < 0) error(1, errno, "failed to create socket 2"); opt = 1; if (setsockopt(fd1, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) error(1, errno, "failed to set SO_REUSEPORT on socket 1"); if (setsockopt(fd2, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) error(1, errno, "failed to set SO_REUSEPORT on socket 2"); attach_ebpf(fd1, 10); attach_ebpf(fd2, 10); if (bind(fd1, addr, sockaddr_size())) error(1, errno, "failed to bind recv socket 1"); if (!bind(fd2, addr, sockaddr_size()) && errno != EADDRINUSE) error(1, errno, "bind socket 2 should fail with EADDRINUSE"); free(addr); }
static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas, struct tftp_t *tp) { struct tftp_session *spt; int k; for (k = 0; k < TFTP_SESSIONS_MAX; k++) { spt = &slirp->tftp_sessions[k]; if (!tftp_session_in_use(spt)) goto found; /* sessions time out after 5 inactive seconds */ if ((int)(curtime - spt->timestamp) > 5000) { tftp_session_terminate(spt); goto found; } } return -1; found: memset(spt, 0, sizeof(*spt)); memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas)); spt->fd = -1; spt->block_size = 512; spt->client_port = tp->udp.uh_sport; spt->slirp = slirp; tftp_session_update(spt); return k; }
static void build_recv_group(const struct test_params p, int fd[], uint16_t mod, void (*attach_bpf)(int, uint16_t)) { struct sockaddr * const addr = new_any_sockaddr(p.recv_family, p.recv_port); int i, opt; for (i = 0; i < p.recv_socks; ++i) { fd[i] = socket(p.recv_family, p.protocol, 0); if (fd[i] < 0) error(1, errno, "failed to create recv %d", i); opt = 1; if (setsockopt(fd[i], SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) error(1, errno, "failed to set SO_REUSEPORT on %d", i); if (i == 0) attach_bpf(fd[i], mod); if (bind(fd[i], addr, sockaddr_size())) error(1, errno, "failed to bind recv socket %d", i); if (p.protocol == SOCK_STREAM) { opt = 4; if (setsockopt(fd[i], SOL_TCP, TCP_FASTOPEN, &opt, sizeof(opt))) error(1, errno, "failed to set TCP_FASTOPEN on %d", i); if (listen(fd[i], p.recv_socks * 10)) error(1, errno, "failed to listen on socket"); } } free(addr); }
/************************************************************************** Try to connect to a server (get_server_address() must be called first!): - try to create a TCP socket and connect it to `server_addr' - if successful: - start monitoring the socket for packets from the server - send a "login request" packet to the server and - return 0 - if unable to create the connection, close the socket, put an error message in ERRBUF and return the Unix error code (ie., errno, which will be non-zero). **************************************************************************/ static int try_to_connect(const char *username, char *errbuf, int errbufsize) { close_socket_set_callback(close_socket_callback); /* connection in progress? wait. */ if (client.conn.used) { (void) mystrlcpy(errbuf, _("Connection in progress."), errbufsize); return -1; } if ((client.conn.sock = socket(server_addr.saddr.sa_family, SOCK_STREAM, 0)) == -1) { (void) mystrlcpy(errbuf, fc_strerror(fc_get_errno()), errbufsize); return -1; } if (fc_connect(client.conn.sock, &server_addr.saddr, sockaddr_size(&server_addr)) == -1) { (void) mystrlcpy(errbuf, fc_strerror(fc_get_errno()), errbufsize); fc_closesocket(client.conn.sock); client.conn.sock = -1; #ifdef HAVE_WINSOCK return -1; #else return errno; #endif } make_connection(client.conn.sock, username); return 0; }
/* * sendto() a socket */ int sosendto(struct socket *so, struct mbuf *m) { int ret; struct sockaddr_storage addr; DEBUG_CALL("sosendto"); DEBUG_ARG("so = %p", so); DEBUG_ARG("m = %p", m); addr = so->fhost.ss; DEBUG_CALL(" sendto()ing)"); sotranslate_out(so, &addr); /* Don't care what port we get */ ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr, sockaddr_size(&addr)); if (ret < 0) return -1; /* * Kill the socket if there's no reply in 4 minutes, * but only if it's an expirable socket */ if (so->so_expire) so->so_expire = curtime + SO_EXPIRE; so->so_state &= SS_PERSISTENT_MASK; so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */ return 0; }
static void test_filter_no_reuseport(const struct test_params p) { struct sockaddr * const addr = new_any_sockaddr(p.recv_family, p.recv_port); const char bpf_license[] = "GPL"; struct bpf_insn ecode[] = { { BPF_ALU64 | BPF_MOV | BPF_K, BPF_REG_0, 0, 0, 10 }, { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 } }; struct sock_filter ccode[] = {{ BPF_RET | BPF_A, 0, 0, 0 }}; union bpf_attr eprog; struct sock_fprog cprog; int fd, bpf_fd; fprintf(stderr, "Testing filters on non-SO_REUSEPORT socket...\n"); memset(&eprog, 0, sizeof(eprog)); eprog.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; eprog.insn_cnt = ARRAY_SIZE(ecode); eprog.insns = (unsigned long) &ecode; eprog.license = (unsigned long) &bpf_license; eprog.kern_version = 0; memset(&cprog, 0, sizeof(cprog)); cprog.len = ARRAY_SIZE(ccode); cprog.filter = ccode; bpf_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &eprog, sizeof(eprog)); if (bpf_fd < 0) error(1, errno, "ebpf error"); fd = socket(p.recv_family, p.protocol, 0); if (fd < 0) error(1, errno, "failed to create socket 1"); if (bind(fd, addr, sockaddr_size())) error(1, errno, "failed to bind recv socket 1"); errno = 0; if (!setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd, sizeof(bpf_fd)) || errno != EINVAL) error(1, errno, "setsockopt should have returned EINVAL"); errno = 0; if (!setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &cprog, sizeof(cprog)) || errno != EINVAL) error(1, errno, "setsockopt should have returned EINVAL"); free(addr); }
static void send_from(struct test_params p, uint16_t sport, char *buf, size_t len) { struct sockaddr * const saddr = new_any_sockaddr(p.send_family, sport); struct sockaddr * const daddr = new_loopback_sockaddr(p.send_family, p.recv_port); const int fd = socket(p.send_family, p.protocol, 0), one = 1; if (fd < 0) error(1, errno, "failed to create send socket"); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) error(1, errno, "failed to set reuseaddr"); if (bind(fd, saddr, sockaddr_size())) error(1, errno, "failed to bind send socket"); if (sendto(fd, buf, len, MSG_FASTOPEN, daddr, sockaddr_size()) < 0) error(1, errno, "failed to send message"); close(fd); free(saddr); free(daddr); }
/************************************************************************** Try to connect to a server (get_server_address() must be called first!): - try to create a TCP socket and connect it to `names' - if successful: - start monitoring the socket for packets from the server - send a "login request" packet to the server and - return 0 - if unable to create the connection, close the socket, put an error message in ERRBUF and return the Unix error code (ie., errno, which will be non-zero). **************************************************************************/ static int try_to_connect(const char *username, char *errbuf, int errbufsize) { int i; int sock = -1; connections_set_close_callback(client_conn_close_callback); /* connection in progress? wait. */ if (client.conn.used) { (void) fc_strlcpy(errbuf, _("Connection in progress."), errbufsize); return -1; } /* Try all (IPv4, IPv6, ...) addresses until we have a connection. */ sock = -1; for (i = 0; i < name_count; i++) { if ((sock = socket(names[i].saddr.sa_family, SOCK_STREAM, 0)) == -1) { /* Probably EAFNOSUPPORT or EPROTONOSUPPORT. */ continue; } if (fc_connect(sock, &names[i].saddr, sockaddr_size(&names[i])) == -1) { fc_closesocket(sock); sock = -1; continue; } else { /* We have a connection! */ break; } } client.conn.sock = sock; if (client.conn.sock == -1) { fc_errno err = fc_get_errno(); /* Save errno value before calling anything */ (void) fc_strlcpy(errbuf, fc_strerror(err), errbufsize); #ifdef HAVE_WINSOCK return -1; #else return err; #endif /* HAVE_WINSOCK */ } make_connection(client.conn.sock, username); return 0; }
/**************************************************************************** Begin a metaserver scan for servers. This just initiates the connection to the metaserver; later get_meta_server_list should be called whenever the socket has data pending to read and parse it. Returns FALSE on error (in which case errbuf will contain an error message). ****************************************************************************/ static bool begin_metaserver_scan(struct server_scan *scan) { union fc_sockaddr addr; int s; scan->meta.urlpath = fc_lookup_httpd(scan->meta.name, &scan->meta.port, metaserver); if (!scan->meta.urlpath) { scan->error_func(scan, _("Invalid $http_proxy or metaserver value, must " "start with 'http://'")); return FALSE; } if (!net_lookup_service(scan->meta.name, scan->meta.port, &addr, FALSE)) { scan->error_func(scan, _("Failed looking up metaserver's host")); return FALSE; } if ((s = socket(addr.saddr.sa_family, SOCK_STREAM, 0)) == -1) { scan->error_func(scan, fc_strerror(fc_get_errno())); return FALSE; } fc_nonblock(s); if (fc_connect(s, &addr.saddr, sockaddr_size(&addr)) == -1) { if (errno == EINPROGRESS) { /* With non-blocking sockets this is the expected result. */ scan->meta.state = META_CONNECTING; scan->sock = s; } else { fc_closesocket(s); scan->error_func(scan, fc_strerror(fc_get_errno())); return FALSE; } } else { /* Instant connection? Whoa. */ scan->sock = s; scan->meta.state = META_CONNECTING; meta_send_request(scan); } return TRUE; }
/************************************************************************** Finds the next (lowest) free port. **************************************************************************/ int find_next_free_port(int starting_port) { int port, s = socket(AF_INET, SOCK_STREAM, 0); for (port = starting_port;; port++) { union fc_sockaddr tmp; struct sockaddr_in *sock = &tmp.saddr_in4; memset(&tmp, 0, sizeof(tmp)); sock->sin_family = AF_INET; sock->sin_port = htons(port); sock->sin_addr.s_addr = htonl(INADDR_ANY); if (bind(s, &tmp.saddr, sockaddr_size(&tmp)) == 0) { break; } } fc_closesocket(s); return port; }
/************************************************************************** Finds the next (lowest) free port. **************************************************************************/ int find_next_free_port(int starting_port, enum fc_addr_family family) { int port; int s; int gafamily; bool found = FALSE; #ifndef IPV6_SUPPORT fc_assert(family == FC_ADDR_IPV4 || family == FC_ADDR_ANY); #endif switch (family) { case FC_ADDR_IPV4: gafamily = AF_INET; break; #ifdef IPV6_SUPPORT case FC_ADDR_IPV6: gafamily = AF_INET6; break; #endif /* IPV6_SUPPORT */ case FC_ADDR_ANY: gafamily = AF_UNSPEC; break; default: fc_assert(FALSE); return -1; } s = socket(gafamily, SOCK_STREAM, 0); for (port = starting_port; !found ; port++) { /* HAVE_GETADDRINFO implies IPv6 support */ #ifdef HAVE_GETADDRINFO struct addrinfo hints; int err; char servname[8]; struct addrinfo *res; fc_snprintf(servname, sizeof(servname), "%d", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = gafamily; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE | FC_AI_NUMERICSERV; err = getaddrinfo(NULL, servname, &hints, &res); if (!err) { struct addrinfo *current = res; while (current != NULL && !found) { if (bind(s, current->ai_addr, current->ai_addrlen) == 0) { found = TRUE; } current = current->ai_next; } freeaddrinfo(res); } #else /* HAVE_GETADDRINFO */ union fc_sockaddr tmp; struct sockaddr_in *sock4; sock4 = &tmp.saddr_in4; memset(&tmp, 0, sizeof(tmp)); sock4->sin_family = AF_INET; sock4->sin_port = htons(port); sock4->sin_addr.s_addr = htonl(INADDR_ANY); if (bind(s, &tmp.saddr, sockaddr_size(&tmp)) == 0) { found = TRUE; } #endif /* HAVE_GETADDRINFO */ } fc_closesocket(s); return port; }
/************************************************************************** Finds the next (lowest) free port. **************************************************************************/ int find_next_free_port(int starting_port, int highest_port, enum fc_addr_family family, char *net_interface, bool not_avail_ok) { int port; int s; int gafamily; bool found = FALSE; #ifndef IPV6_SUPPORT fc_assert(family == FC_ADDR_IPV4 || family == FC_ADDR_ANY); #endif switch (family) { case FC_ADDR_IPV4: gafamily = AF_INET; break; #ifdef IPV6_SUPPORT case FC_ADDR_IPV6: gafamily = AF_INET6; break; #endif /* IPV6_SUPPORT */ case FC_ADDR_ANY: gafamily = AF_UNSPEC; break; default: fc_assert(FALSE); log_error("Port from unsupported address family requested!"); return -1; } for (port = starting_port; !found && highest_port > port; port++) { /* HAVE_GETADDRINFO implies IPv6 support */ #ifdef HAVE_GETADDRINFO struct addrinfo hints; int err; char servname[8]; struct addrinfo *res; fc_snprintf(servname, sizeof(servname), "%d", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = gafamily; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE | FC_AI_NUMERICSERV; err = getaddrinfo(net_interface, servname, &hints, &res); if (!err) { struct addrinfo *current = res; bool unusable = FALSE; while (current != NULL && !unusable) { s = socket(current->ai_family, SOCK_STREAM, 0); if (s == -1) { log_error("socket(): %s", fc_strerror(fc_get_errno())); } else { if (bind(s, current->ai_addr, current->ai_addrlen) != 0) { if (!not_avail_ok || fc_get_errno() != EADDRNOTAVAIL) { unusable = TRUE; } } } current = current->ai_next; fc_closesocket(s); } freeaddrinfo(res); if (!unusable && res != NULL) { found = TRUE; } } #else /* HAVE_GETADDRINFO */ union fc_sockaddr tmp; struct sockaddr_in *sock4; s = socket(gafamily, SOCK_STREAM, 0); sock4 = &tmp.saddr_in4; memset(&tmp, 0, sizeof(tmp)); sock4->sin_family = AF_INET; sock4->sin_port = htons(port); if (net_interface != NULL) { #if defined(HAVE_INET_ATON) if (inet_aton(net_interface, &sock4->sin_addr) == 0) { #else /* HAVE_INET_ATON */ sock4->sin_addr.s_addr = inet_addr(net_interface); if (sock4->sin_addr.s_addr == INADDR_NONE) { #endif /* HAVE_INET_ATON */ struct hostent *hp; hp = gethostbyname(net_interface); if (hp == NULL) { log_error("No hostent for %s!", net_interface); return -1; } if (hp->h_addrtype != AF_INET) { log_error("Requested IPv4 address for %s, got something else! (%d)", net_interface, hp->h_addrtype); return -1; } memcpy(&sock4->sin_addr, hp->h_addr, hp->h_length); } } else { sock4->sin_addr.s_addr = htonl(INADDR_ANY); } if (bind(s, &tmp.saddr, sockaddr_size(&tmp)) == 0) { found = TRUE; } fc_closesocket(s); #endif /* HAVE_GETADDRINFO */ } if (!found) { log_error("None of the ports %d - %d is available.", starting_port, highest_port); return -1; } /* Rollback the last increment from the loop, back to the port * number found to be free. */ port--; return port; }