From: Yaroslav K Date: Wed, 26 Feb 2020 20:58:13 +0000 (-0800) Subject: add setting IP DiffServ Codepoint (DSCP, previously TOS) on sockets X-Git-Tag: release-1.11.0~84^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F200%2Fhead;p=thirdparty%2Funbound.git add setting IP DiffServ Codepoint (DSCP, previously TOS) on sockets --- diff --git a/daemon/remote.c b/daemon/remote.c index f4b7298cb..b0ac2bb5b 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -329,7 +329,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, /* open fd */ fd = create_tcp_accept_sock(res, 1, &noproto, 0, - cfg->ip_transparent, 0, cfg->ip_freebind, cfg->use_systemd); + cfg->ip_transparent, 0, cfg->ip_freebind, cfg->use_systemd, cfg->ip_dscp); freeaddrinfo(res); } diff --git a/daemon/worker.c b/daemon/worker.c index cec6bcd66..201e77336 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1808,7 +1808,7 @@ worker_init(struct worker* worker, struct config_file *cfg, worker->back = outside_network_create(worker->base, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, - cfg->do_tcp?cfg->outgoing_num_tcp:0, + cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, worker->daemon->env->infra_cache, worker->rndstate, cfg->use_caps_bits_for_id, worker->ports, worker->numports, cfg->unwanted_threshold, cfg->outgoing_tcp_mss, diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 66ea7c3ba..24233f1d0 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -233,7 +233,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) w->back = outside_network_create(w->base, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, - cfg->do_tcp?cfg->outgoing_num_tcp:0, + cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, ports, numports, cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w, diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 7e2afd843..61a632106 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -179,9 +179,10 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, int snd, int listen, int* reuseport, int transparent, - int freebind, int use_systemd) + int freebind, int use_systemd, int dscp) { int s; + char* err; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined (SO_BINDANY) int on=1; #endif @@ -451,6 +452,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, # endif #endif /* SO_SNDBUF */ } + err = set_ip_dscp(s, family, dscp); + if(err != NULL) + log_warn("error setting IP DiffServ codepoint %d on UDP socket: %s", dscp, err); if(family == AF_INET6) { # if defined(IPV6_V6ONLY) if(v6only) { @@ -638,9 +642,10 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport, int transparent, int mss, int freebind, int use_systemd) + int* reuseport, int transparent, int mss, int freebind, int use_systemd, int dscp) { int s; + char* err; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined(SO_BINDANY) int on = 1; #endif @@ -793,6 +798,9 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, strerror(errno)); } #endif /* IP_TRANSPARENT || IP_BINDANY || SO_BINDANY */ + err = set_ip_dscp(s, addr->ai_family, dscp); + if(err != NULL) + log_warn("error setting IP DiffServ codepoint %d on TCP socket: %s", dscp, err); if( #ifdef HAVE_SYSTEMD !got_fd_from_systemd && @@ -866,6 +874,48 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, return s; } +char* +set_ip_dscp(int socket, int addrfamily, int dscp) { + int ds; + + if(dscp == 0) + return NULL; + ds = dscp << 2; + switch(addrfamily) { + case AF_INET6: + if(setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)) < 0) + return sock_strerror(errno); + default: + if(setsockopt(socket, IPPROTO_IP, IP_TOS, &ds, sizeof(ds)) < 0) + return sock_strerror(errno); + } + return NULL; +} + +# ifndef USE_WINSOCK +char* +sock_strerror(int errn){ + return strerror(errno); +} + +void +sock_close(int socket) { + close(socket); +} + +# else +char* +sock_strerror(int errn){ + return wsa_strerror(WSAGetLastError())) +} + +void +sock_close(int socket) { + closesocket(socket); +} + +# endif /* USE_WINSOCK */ + int create_local_accept_sock(const char *path, int* noproto, int use_systemd) { @@ -952,7 +1002,7 @@ err: static int make_sock(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd) + int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd, int dscp) { struct addrinfo *res = NULL; int r, s, inuse, noproto; @@ -980,7 +1030,7 @@ make_sock(int stype, const char* ifname, const char* port, s = create_udp_sock(res->ai_family, res->ai_socktype, (struct sockaddr*)res->ai_addr, res->ai_addrlen, v6only, &inuse, &noproto, (int)rcv, (int)snd, 1, - reuseport, transparent, freebind, use_systemd); + reuseport, transparent, freebind, use_systemd, dscp); if(s == -1 && inuse) { log_err("bind: address already in use"); } else if(s == -1 && noproto && hints->ai_family == AF_INET6){ @@ -988,7 +1038,7 @@ make_sock(int stype, const char* ifname, const char* port, } } else { s = create_tcp_accept_sock(res, v6only, &noproto, reuseport, - transparent, tcp_mss, freebind, use_systemd); + transparent, tcp_mss, freebind, use_systemd, dscp); if(s == -1 && noproto && hints->ai_family == AF_INET6){ *noip6 = 1; } @@ -1001,7 +1051,7 @@ make_sock(int stype, const char* ifname, const char* port, static int make_sock_port(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd) + int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd, int dscp) { char* s = strchr(ifname, '@'); if(s) { @@ -1023,10 +1073,10 @@ make_sock_port(int stype, const char* ifname, const char* port, (void)strlcpy(p, s+1, sizeof(p)); p[strlen(s+1)]=0; return make_sock(stype, newif, p, hints, v6only, noip6, - rcv, snd, reuseport, transparent, tcp_mss, freebind, use_systemd); + rcv, snd, reuseport, transparent, tcp_mss, freebind, use_systemd, dscp); } return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd, - reuseport, transparent, tcp_mss, freebind, use_systemd); + reuseport, transparent, tcp_mss, freebind, use_systemd, dscp); } /** @@ -1154,7 +1204,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, size_t rcv, size_t snd, int ssl_port, struct config_strlist* tls_additional_port, int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd, - int dnscrypt_port) + int dnscrypt_port, int dscp) { int s, noip6=0; #ifdef USE_DNSCRYPT @@ -1171,7 +1221,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if(do_auto) { if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, freebind, use_systemd)) == -1) { + tcp_mss, freebind, use_systemd, dscp)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -1200,7 +1250,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, /* regular udp socket */ if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, freebind, use_systemd)) == -1) { + tcp_mss, freebind, use_systemd, dscp)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -1222,7 +1272,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, tls_additional_port); if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, &noip6, 0, 0, reuseport, transparent, tcp_mss, - freebind, use_systemd)) == -1) { + freebind, use_systemd, dscp)) == -1) { if(noip6) { /*log_warn("IPv6 protocol not available");*/ return 1; @@ -1421,7 +1471,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } @@ -1435,7 +1485,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } @@ -1451,7 +1501,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } @@ -1465,7 +1515,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index ad84d8322..c3cc0a92d 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -209,7 +209,7 @@ void listen_start_accept(struct listen_dnsport* listen); */ int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, - int snd, int listen, int* reuseport, int transparent, int freebind, int use_systemd); + int snd, int listen, int* reuseport, int transparent, int freebind, int use_systemd, int dscp); /** * Create and bind TCP listening socket @@ -225,7 +225,7 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, * @return: the socket. -1 on error. */ int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport, int transparent, int mss, int freebind, int use_systemd); + int* reuseport, int transparent, int mss, int freebind, int use_systemd, int dscp); /** * Create and bind local listening socket @@ -367,4 +367,7 @@ int tcp_req_info_handle_read_close(struct tcp_req_info* req); /** get the size of currently used tcp stream wait buffers (in bytes) */ size_t tcp_req_info_get_stream_buffer_size(void); +char* set_ip_dscp(int socket, int addrfamily, int ds); +char* sock_strerror(int errn); + #endif /* LISTEN_DNSPORT_H */ diff --git a/services/outside_network.c b/services/outside_network.c index b2c67766e..978e98b0e 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -205,18 +205,25 @@ pick_outgoing_tcp(struct waiting_tcp* w, int s) /** get TCP file descriptor for address, returns -1 on failure, * tcp_mss is 0 or maxseg size to set for TCP packets. */ int -outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss) +outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp) { int s; + int af; + char* err; #ifdef SO_REUSEADDR int on = 1; #endif #ifdef INET6 - if(addr_is_ip6(addr, addrlen)) + if(addr_is_ip6(addr, addrlen)){ s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); - else + af = AF_INET6; + } else { +#else + { #endif + af = AF_INET; s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + } if(s == -1) { #ifndef USE_WINSOCK log_err_addr("outgoing tcp: socket", strerror(errno), @@ -236,6 +243,12 @@ outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss) } #endif + err = set_ip_dscp(s, af, dscp); + if(err != NULL) { + verbose(VERB_ALGO, "outgoing tcp:" + "error setting IP DiffServ codepoint on socket"); + } + if(tcp_mss > 0) { #if defined(IPPROTO_TCP) && defined(TCP_MAXSEG) if(setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, @@ -291,7 +304,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len) log_assert(pkt); log_assert(w->addrlen > 0); /* open socket */ - s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss); + s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss, w->outnet->ip_dscp); if(s == -1) return 0; @@ -719,7 +732,7 @@ static int setup_if(struct port_if* pif, const char* addrstr, struct outside_network* outside_network_create(struct comm_base *base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, - int do_ip6, size_t num_tcp, struct infra_cache* infra, + int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, struct ub_randstate* rnd, int use_caps_for_id, int* availports, int numavailports, size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, @@ -752,6 +765,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, outnet->use_caps_for_id = use_caps_for_id; outnet->do_udp = do_udp; outnet->tcp_mss = tcp_mss; + outnet->ip_dscp = dscp; #ifndef S_SPLINT_S if(delayclose) { outnet->delayclose = 1; @@ -1041,7 +1055,7 @@ sai6_putrandom(struct sockaddr_in6 *sa, int pfxlen, struct ub_randstate *rnd) */ static int udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, - int port, int* inuse, struct ub_randstate* rnd) + int port, int* inuse, struct ub_randstate* rnd, int dscp) { int fd, noproto; if(addr_is_ip6(addr, addrlen)) { @@ -1056,13 +1070,13 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, } fd = create_udp_sock(AF_INET6, SOCK_DGRAM, (struct sockaddr*)&sa, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL, 0, freebind, 0); + 0, 0, 0, NULL, 0, freebind, 0, dscp); } else { struct sockaddr_in* sa = (struct sockaddr_in*)addr; sa->sin_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL, 0, 0, 0); + 0, 0, 0, NULL, 0, 0, 0, dscp); } return fd; } @@ -1127,7 +1141,7 @@ select_ifport(struct outside_network* outnet, struct pending* pend, my_port = portno = 0; #endif fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, - portno, &inuse, outnet->rnd); + portno, &inuse, outnet->rnd, outnet->ip_dscp); if(fd == -1 && !inuse) { /* nonrecoverable error making socket */ return 0; @@ -2176,10 +2190,11 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, { struct sockaddr_storage* addr; socklen_t addrlen; - int i, try, pnum; + int i, try, pnum, dscp; struct port_if* pif; /* create fd */ + dscp = outnet->ip_dscp; for(try = 0; try<1000; try++) { int port = 0; int freebind = 0; @@ -2226,13 +2241,13 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, sa.sin6_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET6, SOCK_DGRAM, (struct sockaddr*)&sa, addrlen, 1, &inuse, &noproto, - 0, 0, 0, NULL, 0, freebind, 0); + 0, 0, 0, NULL, 0, freebind, 0, dscp); } else { struct sockaddr_in* sa = (struct sockaddr_in*)addr; sa->sin_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, &inuse, &noproto, - 0, 0, 0, NULL, 0, freebind, 0); + 0, 0, 0, NULL, 0, freebind, 0, dscp); } if(fd != -1) { return fd; @@ -2324,7 +2339,7 @@ outnet_comm_point_for_tcp(struct outside_network* outnet, sldns_buffer* query, int timeout, int ssl, char* host) { struct comm_point* cp; - int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss); + int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss, outnet->ip_dscp); if(fd == -1) { return 0; } @@ -2386,7 +2401,7 @@ outnet_comm_point_for_http(struct outside_network* outnet, { /* cp calls cb with err=NETEVENT_DONE when transfer is done */ struct comm_point* cp; - int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss); + int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss, outnet->ip_dscp); if(fd == -1) { return 0; } diff --git a/services/outside_network.h b/services/outside_network.h index f12b2e5be..3fc5dde45 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -138,6 +138,8 @@ struct outside_network { #endif /** maximum segment size of tcp socket */ int tcp_mss; + /** IP_TOS socket option requested on the sockets */ + int ip_dscp; /** * Array of tcp pending used for outgoing TCP connections. @@ -419,7 +421,7 @@ struct serviced_query { */ struct outside_network* outside_network_create(struct comm_base* base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, - int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra, + int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, struct ub_randstate* rnd, int use_caps_for_id, int* availports, int numavailports, size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, @@ -542,7 +544,7 @@ size_t serviced_get_mem(struct serviced_query* sq); /** get TCP file descriptor for address, returns -1 on failure, * tcp_mss is 0 or maxseg size to set for TCP packets. */ -int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss); +int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp); /** * Create udp commpoint suitable for sending packets to the destination. diff --git a/testcode/fake_event.c b/testcode/fake_event.c index d6e904a4d..c69fb9bfd 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1031,6 +1031,7 @@ outside_network_create(struct comm_base* base, size_t bufsize, size_t ATTR_UNUSED(num_ports), char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), int ATTR_UNUSED(do_ip6), size_t ATTR_UNUSED(num_tcp), + int ATTR_UNUSED(dscp), struct infra_cache* infra, struct ub_randstate* ATTR_UNUSED(rnd), int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), @@ -1583,7 +1584,7 @@ int create_udp_sock(int ATTR_UNUSED(family), int ATTR_UNUSED(socktype), int* ATTR_UNUSED(noproto), int ATTR_UNUSED(rcv), int ATTR_UNUSED(snd), int ATTR_UNUSED(listen), int* ATTR_UNUSED(reuseport), int ATTR_UNUSED(transparent), int ATTR_UNUSED(freebind), - int ATTR_UNUSED(use_systemd)) + int ATTR_UNUSED(use_systemd), int ATTR_UNUSED(dscp)) { /* if you actually print to this, it'll be stdout during test */ return 1; @@ -1790,7 +1791,7 @@ int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet, } int outnet_get_tcp_fd(struct sockaddr_storage* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(tcp_mss)) + socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(tcp_mss), int ATTR_UNUSED(dscp)) { log_assert(0); return -1;