diff --git a/daemon/worker.c b/daemon/worker.c index 181441c36..ffe7ff2d4 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1167,9 +1167,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } #endif #ifdef USE_DNSTAP - if(worker->dtenv.log_client_query_messages) - dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type, - c->buffer); + /* + * sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler + */ + if(worker->dtenv.log_client_query_messages) { + log_addr(VERB_ALGO, "request from client", &repinfo->addr, repinfo->addrlen); + log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); + dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer); + } #endif acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr, repinfo->addrlen); @@ -1593,9 +1598,14 @@ send_reply_rc: if(is_secure_answer) worker->stats.ans_secure++; } #ifdef USE_DNSTAP - if(worker->dtenv.log_client_response_messages) - dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, - c->type, c->buffer); + /* + * sending src (client)/dst (local service) addresses over DNSTAP from send_reply code label (when we serviced local zone for ex.) + */ + if(worker->dtenv.log_client_response_messages) { + log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); + log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen); + dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer); + } #endif if(worker->env.cfg->log_replies) { diff --git a/dnstap/dnstap.c b/dnstap/dnstap.c index b8a321670..6577a019a 100644 --- a/dnstap/dnstap.c +++ b/dnstap/dnstap.c @@ -302,44 +302,75 @@ dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has) static void dt_msg_fill_net(struct dt_msg *dm, - struct sockaddr_storage *ss, + struct sockaddr_storage *qs, + struct sockaddr_storage *rs, enum comm_point_type cptype, - ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr, - uint32_t *port, protobuf_c_boolean *has_port) + ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr, + uint32_t *qport, protobuf_c_boolean *has_qport, + ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr, + uint32_t *rport, protobuf_c_boolean *has_rport) { - log_assert(ss->ss_family == AF_INET6 || ss->ss_family == AF_INET); - if (ss->ss_family == AF_INET6) { - struct sockaddr_in6 *s = (struct sockaddr_in6 *) ss; + log_assert(qs->ss_family == AF_INET6 || qs->ss_family == AF_INET); + if (qs->ss_family == AF_INET6) { + struct sockaddr_in6 *q = (struct sockaddr_in6 *) qs; /* socket_family */ dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6; dm->m.has_socket_family = 1; /* addr: query_address or response_address */ - addr->data = s->sin6_addr.s6_addr; - addr->len = 16; /* IPv6 */ - *has_addr = 1; + qaddr->data = q->sin6_addr.s6_addr; + qaddr->len = 16; /* IPv6 */ + *has_qaddr = 1; /* port: query_port or response_port */ - *port = ntohs(s->sin6_port); - *has_port = 1; - } else if (ss->ss_family == AF_INET) { - struct sockaddr_in *s = (struct sockaddr_in *) ss; + *qport = ntohs(q->sin6_port); + *has_qport = 1; + } else if (qs->ss_family == AF_INET) { + struct sockaddr_in *q = (struct sockaddr_in *) qs; /* socket_family */ dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET; dm->m.has_socket_family = 1; /* addr: query_address or response_address */ - addr->data = (uint8_t *) &s->sin_addr.s_addr; - addr->len = 4; /* IPv4 */ - *has_addr = 1; + qaddr->data = (uint8_t *) &q->sin_addr.s_addr; + qaddr->len = 4; /* IPv4 */ + *has_qaddr = 1; /* port: query_port or response_port */ - *port = ntohs(s->sin_port); - *has_port = 1; + *qport = ntohs(q->sin_port); + *has_qport = 1; } + /* + * This block is to fill second set of fields in DNSTAP-message defined as request_/response_ names. + * Additional responsive structure is: struct sockaddr_storage *rs + */ + if (rs && rs->ss_family == AF_INET6) { + struct sockaddr_in6 *r = (struct sockaddr_in6 *) rs; + + /* addr: query_address or response_address */ + raddr->data = r->sin6_addr.s6_addr; + raddr->len = 16; /* IPv6 */ + *has_raddr = 1; + + /* port: query_port or response_port */ + *rport = ntohs(r->sin6_port); + *has_rport = 1; + } else if (rs && rs->ss_family == AF_INET) { + struct sockaddr_in *r = (struct sockaddr_in *) rs; + + /* addr: query_address or response_address */ + raddr->data = (uint8_t *) &r->sin_addr.s_addr; + raddr->len = 4; /* IPv4 */ + *has_raddr = 1; + + /* port: query_port or response_port */ + *rport = ntohs(r->sin_port); + *has_rport = 1; + } + log_assert(cptype == comm_udp || cptype == comm_tcp); if (cptype == comm_udp) { /* socket_protocol */ @@ -355,6 +386,7 @@ dt_msg_fill_net(struct dt_msg *dm, void dt_msg_send_client_query(struct dt_env *env, struct sockaddr_storage *qsock, + struct sockaddr_storage *rsock, enum comm_point_type cptype, sldns_buffer *qmsg) { @@ -374,11 +406,14 @@ dt_msg_send_client_query(struct dt_env *env, /* query_message */ dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); - /* socket_family, socket_protocol, query_address, query_port */ + /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */ log_assert(cptype == comm_udp || cptype == comm_tcp); - dt_msg_fill_net(&dm, qsock, cptype, + dt_msg_fill_net(&dm, qsock, rsock, cptype, &dm.m.query_address, &dm.m.has_query_address, - &dm.m.query_port, &dm.m.has_query_port); + &dm.m.query_port, &dm.m.has_query_port, + &dm.m.response_address, &dm.m.has_response_address, + &dm.m.response_port, &dm.m.has_response_port); + if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); @@ -387,6 +422,7 @@ dt_msg_send_client_query(struct dt_env *env, void dt_msg_send_client_response(struct dt_env *env, struct sockaddr_storage *qsock, + struct sockaddr_storage *rsock, enum comm_point_type cptype, sldns_buffer *rmsg) { @@ -406,11 +442,13 @@ dt_msg_send_client_response(struct dt_env *env, /* response_message */ dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); - /* socket_family, socket_protocol, query_address, query_port */ + /* socket_family, socket_protocol, query_address, query_port, response_address, response_port */ log_assert(cptype == comm_udp || cptype == comm_tcp); - dt_msg_fill_net(&dm, qsock, cptype, + dt_msg_fill_net(&dm, qsock, rsock, cptype, &dm.m.query_address, &dm.m.has_query_address, - &dm.m.query_port, &dm.m.has_query_port); + &dm.m.query_port, &dm.m.has_query_port, + &dm.m.response_address, &dm.m.has_response_address, + &dm.m.response_port, &dm.m.has_response_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); @@ -419,6 +457,7 @@ dt_msg_send_client_response(struct dt_env *env, void dt_msg_send_outside_query(struct dt_env *env, struct sockaddr_storage *rsock, + struct sockaddr_storage *qsock, enum comm_point_type cptype, uint8_t *zone, size_t zone_len, sldns_buffer *qmsg) @@ -454,11 +493,13 @@ dt_msg_send_outside_query(struct dt_env *env, /* query_message */ dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); - /* socket_family, socket_protocol, response_address, response_port */ + /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */ log_assert(cptype == comm_udp || cptype == comm_tcp); - dt_msg_fill_net(&dm, rsock, cptype, + dt_msg_fill_net(&dm, rsock, qsock, cptype, &dm.m.response_address, &dm.m.has_response_address, - &dm.m.response_port, &dm.m.has_response_port); + &dm.m.response_port, &dm.m.has_response_port, + &dm.m.query_address, &dm.m.has_query_address, + &dm.m.query_port, &dm.m.has_query_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); @@ -467,6 +508,7 @@ dt_msg_send_outside_query(struct dt_env *env, void dt_msg_send_outside_response(struct dt_env *env, struct sockaddr_storage *rsock, + struct sockaddr_storage *qsock, enum comm_point_type cptype, uint8_t *zone, size_t zone_len, uint8_t *qbuf, size_t qbuf_len, @@ -510,11 +552,13 @@ dt_msg_send_outside_response(struct dt_env *env, /* response_message */ dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message); - /* socket_family, socket_protocol, response_address, response_port */ + /* socket_family, socket_protocol, response_address, response_port, query_address, query_port */ log_assert(cptype == comm_udp || cptype == comm_tcp); - dt_msg_fill_net(&dm, rsock, cptype, + dt_msg_fill_net(&dm, rsock, qsock, cptype, &dm.m.response_address, &dm.m.has_response_address, - &dm.m.response_port, &dm.m.has_response_port); + &dm.m.response_port, &dm.m.has_response_port, + &dm.m.query_address, &dm.m.has_query_address, + &dm.m.query_port, &dm.m.has_query_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); diff --git a/dnstap/dnstap.h b/dnstap/dnstap.h index 783b8c514..449fae727 100644 --- a/dnstap/dnstap.h +++ b/dnstap/dnstap.h @@ -123,12 +123,14 @@ dt_delete(struct dt_env *env); * Create and send a new dnstap "Message" event of type CLIENT_QUERY. * @param env: dnstap environment object. * @param qsock: address/port of client. + * @param rsock: local (service) address/port. * @param cptype: comm_udp or comm_tcp. * @param qmsg: query message. */ void dt_msg_send_client_query(struct dt_env *env, struct sockaddr_storage *qsock, + struct sockaddr_storage *rsock, enum comm_point_type cptype, struct sldns_buffer *qmsg); @@ -136,12 +138,14 @@ dt_msg_send_client_query(struct dt_env *env, * Create and send a new dnstap "Message" event of type CLIENT_RESPONSE. * @param env: dnstap environment object. * @param qsock: address/port of client. + * @param rsock: local (service) address/port. * @param cptype: comm_udp or comm_tcp. * @param rmsg: response message. */ void dt_msg_send_client_response(struct dt_env *env, struct sockaddr_storage *qsock, + struct sockaddr_storage *rsock, enum comm_point_type cptype, struct sldns_buffer *rmsg); @@ -150,7 +154,8 @@ dt_msg_send_client_response(struct dt_env *env, * FORWARDER_QUERY. The type used is dependent on the value of the RD bit * in the query header. * @param env: dnstap environment object. - * @param rsock: address/port of server the query is being sent to. + * @param rsock: address/port of server (upstream) the query is being sent to. + * @param qsock: address/port of server (local) the query is being sent from. * @param cptype: comm_udp or comm_tcp. * @param zone: query zone. * @param zone_len: length of zone. @@ -159,6 +164,7 @@ dt_msg_send_client_response(struct dt_env *env, void dt_msg_send_outside_query(struct dt_env *env, struct sockaddr_storage *rsock, + struct sockaddr_storage *qsock, enum comm_point_type cptype, uint8_t *zone, size_t zone_len, struct sldns_buffer *qmsg); @@ -168,7 +174,8 @@ dt_msg_send_outside_query(struct dt_env *env, * FORWARDER_RESPONSE. The type used is dependent on the value of the RD bit * in the query header. * @param env: dnstap environment object. - * @param rsock: address/port of server the response was received from. + * @param rsock: address/port of server (upstream) the response was received from. + * @param qsock: address/port of server (local) the response was received to. * @param cptype: comm_udp or comm_tcp. * @param zone: query zone. * @param zone_len: length of zone. @@ -181,6 +188,7 @@ dt_msg_send_outside_query(struct dt_env *env, void dt_msg_send_outside_response(struct dt_env *env, struct sockaddr_storage *rsock, + struct sockaddr_storage *qsock, enum comm_point_type cptype, uint8_t *zone, size_t zone_len, uint8_t *qbuf, size_t qbuf_len, diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 64d22d4d8..2d6155699 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -133,6 +133,16 @@ verbose_print_addr(struct addrinfo *addr) } } +void +verbose_print_unbound_socket(struct unbound_socket* ub_sock) +{ + if(verbosity >= VERB_ALGO) { + log_info("listing of unbound_socket structure:"); + verbose_print_addr(ub_sock->addr); + log_info("s is: %d, fam is: %s", ub_sock->s, ub_sock->fam == AF_INET?"AF_INET":"AF_INET6"); + } +} + #ifdef HAVE_SYSTEMD static int systemd_get_activated(int family, int socktype, int listen, @@ -916,7 +926,7 @@ 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 nodelay, int freebind, - int use_systemd, int dscp) + int use_systemd, int dscp, struct unbound_socket* ub_sock) { struct addrinfo *res = NULL; int r, s, inuse, noproto; @@ -958,7 +968,11 @@ make_sock(int stype, const char* ifname, const char* port, *noip6 = 1; } } - freeaddrinfo(res); + + ub_sock->addr = res; + ub_sock->s = s; + ub_sock->fam = hints->ai_family; + return s; } @@ -967,7 +981,7 @@ 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 nodelay, int freebind, - int use_systemd, int dscp) + int use_systemd, int dscp, struct unbound_socket* ub_sock) { char* s = strchr(ifname, '@'); if(s) { @@ -990,11 +1004,11 @@ make_sock_port(int stype, const char* ifname, const char* port, p[strlen(s+1)]=0; return make_sock(stype, newif, p, hints, v6only, noip6, rcv, snd, reuseport, transparent, tcp_mss, nodelay, freebind, - use_systemd, dscp); + use_systemd, dscp, ub_sock); } return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd, reuseport, transparent, tcp_mss, nodelay, freebind, use_systemd, - dscp); + dscp, ub_sock); } /** @@ -1002,10 +1016,11 @@ make_sock_port(int stype, const char* ifname, const char* port, * @param list: list head. changed. * @param s: fd. * @param ftype: if fd is UDP. + * @param ub_sock: socket with address. * @return false on failure. list in unchanged then. */ static int -port_insert(struct listen_port** list, int s, enum listen_type ftype) +port_insert(struct listen_port** list, int s, enum listen_type ftype, struct unbound_socket* ub_sock) { struct listen_port* item = (struct listen_port*)malloc( sizeof(struct listen_port)); @@ -1014,6 +1029,7 @@ port_insert(struct listen_port** list, int s, enum listen_type ftype) item->next = *list; item->fd = s; item->ftype = ftype; + item->socket = ub_sock; *list = item; return 1; } @@ -1043,7 +1059,7 @@ set_recvpktinfo(int s, int family) return 0; } # else - log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please " + log_err("no IPV6_RECVPKTINFO and IPV6_PKTINFO options, please " "disable interface-automatic or do-ip6 in config"); return 0; # endif /* defined IPV6_RECVPKTINFO */ @@ -1130,6 +1146,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, int s, noip6=0; int is_https = if_is_https(ifname, port, https_port); int nodelay = is_https && http2_nodelay; + struct unbound_socket* ub_sock; #ifdef USE_DNSCRYPT int is_dnscrypt = ((strchr(ifname, '@') && atoi(strchr(ifname, '@')+1) == dnscrypt_port) || @@ -1141,10 +1158,15 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if(!do_udp && !do_tcp) return 0; + if(do_auto) { + ub_sock = calloc(1, sizeof(struct unbound_socket)); + if(!ub_sock) + return 0; if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, nodelay, freebind, use_systemd, dscp)) == -1) { + tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) { + free(ub_sock); if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -1154,18 +1176,24 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, /* getting source addr packet info is highly non-portable */ if(!set_recvpktinfo(s, hints->ai_family)) { sock_close(s); + free(ub_sock); return 0; } if(!port_insert(list, s, - is_dnscrypt?listen_type_udpancil_dnscrypt:listen_type_udpancil)) { + is_dnscrypt?listen_type_udpancil_dnscrypt:listen_type_udpancil, ub_sock)) { sock_close(s); + free(ub_sock); return 0; } } else if(do_udp) { + ub_sock = calloc(1, sizeof(struct unbound_socket)); + if(!ub_sock) + return 0; /* regular udp socket */ if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, nodelay, freebind, use_systemd, dscp)) == -1) { + tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) { + free(ub_sock); if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -1173,8 +1201,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, return 0; } if(!port_insert(list, s, - is_dnscrypt?listen_type_udp_dnscrypt:listen_type_udp)) { + is_dnscrypt?listen_type_udp_dnscrypt:listen_type_udp, ub_sock)) { sock_close(s); + free(ub_sock); return 0; } } @@ -1182,6 +1211,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, int is_ssl = if_is_ssl(ifname, port, ssl_port, tls_additional_port); enum listen_type port_type; + ub_sock = calloc(1, sizeof(struct unbound_socket)); + if(!ub_sock) + return 0; if(is_ssl) port_type = listen_type_ssl; else if(is_https) @@ -1192,7 +1224,8 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, port_type = listen_type_tcp; if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, &noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay, - freebind, use_systemd, dscp)) == -1) { + freebind, use_systemd, dscp, ub_sock)) == -1) { + free(ub_sock); if(noip6) { /*log_warn("IPv6 protocol not available");*/ return 1; @@ -1201,8 +1234,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, } if(is_ssl) verbose(VERB_ALGO, "setup TCP for SSL service"); - if(!port_insert(list, s, port_type)) { + if(!port_insert(list, s, port_type, ub_sock)) { sock_close(s); + free(ub_sock); return 0; } } @@ -1268,14 +1302,14 @@ listen_create(struct comm_base* base, struct listen_port* ports, if(ports->ftype == listen_type_udp || ports->ftype == listen_type_udp_dnscrypt) cp = comm_point_create_udp(base, ports->fd, - front->udp_buff, cb, cb_arg); + front->udp_buff, cb, cb_arg, ports->socket); else if(ports->ftype == listen_type_tcp || ports->ftype == listen_type_tcp_dnscrypt) cp = comm_point_create_tcp(base, ports->fd, tcp_accept_count, tcp_idle_timeout, harden_large_queries, 0, NULL, tcp_conn_limit, bufsize, front->udp_buff, - ports->ftype, cb, cb_arg); + ports->ftype, cb, cb_arg, ports->socket); else if(ports->ftype == listen_type_ssl || ports->ftype == listen_type_http) { cp = comm_point_create_tcp(base, ports->fd, @@ -1283,7 +1317,7 @@ listen_create(struct comm_base* base, struct listen_port* ports, harden_large_queries, http_max_streams, http_endpoint, tcp_conn_limit, bufsize, front->udp_buff, - ports->ftype, cb, cb_arg); + ports->ftype, cb, cb_arg, ports->socket); if(http_notls && ports->ftype == listen_type_http) cp->ssl = NULL; else @@ -1310,7 +1344,7 @@ listen_create(struct comm_base* base, struct listen_port* ports, } else if(ports->ftype == listen_type_udpancil || ports->ftype == listen_type_udpancil_dnscrypt) cp = comm_point_create_udp_ancil(base, ports->fd, - front->udp_buff, cb, cb_arg); + front->udp_buff, cb, cb_arg, ports->socket); if(!cp) { log_err("can't create commpoint"); listen_delete(front); @@ -1644,6 +1678,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, } } } + return list; } @@ -1655,6 +1690,8 @@ void listening_ports_free(struct listen_port* list) if(list->fd != -1) { sock_close(list->fd); } + freeaddrinfo(list->socket->addr); + free(list->socket); free(list); list = nx; } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index f438ff458..cb614c834 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -102,6 +102,18 @@ enum listen_type { listen_type_http }; +/* + * socket properties (just like NSD nsd_socket structure definition) + */ +struct unbound_socket { + /** socket-address structure */ + struct addrinfo * addr; + /** socket descriptor returned by socket() syscall */ + int s; + /** address family (AF_INET/IF_INET6) */ + int fam; +}; + /** * Single linked list to store shared ports that have been * opened for use by all threads. @@ -113,6 +125,8 @@ struct listen_port { int fd; /** type of file descriptor, udp or tcp */ enum listen_type ftype; + /** fill in unbpound_socket structure for every opened socket at Unbound startup */ + struct unbound_socket* socket; }; /** @@ -424,4 +438,9 @@ int http2_submit_dns_response(void* v); char* set_ip_dscp(int socket, int addrfamily, int ds); +/** for debug and profiling purposes only + * @param ub_sock: the structure containing created socket info we want to print or log for + */ +void verbose_print_unbound_socket(struct unbound_socket* ub_sock); + #endif /* LISTEN_DNSPORT_H */ diff --git a/services/outside_network.c b/services/outside_network.c index 3687b5fea..18e2c8da9 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -198,15 +198,17 @@ waiting_tcp_delete(struct waiting_tcp* w) * Pick random outgoing-interface of that family, and bind it. * port set to 0 so OS picks a port number for us. * if it is the ANY address, do not bind. + * @param pend: pending tcp structure, for storing the local address choice. * @param w: tcp structure with destination address. * @param s: socket fd. * @return false on error, socket closed. */ static int -pick_outgoing_tcp(struct waiting_tcp* w, int s) +pick_outgoing_tcp(struct pending_tcp* pend, struct waiting_tcp* w, int s) { struct port_if* pi = NULL; int num; + pend->pi = NULL; #ifdef INET6 if(addr_is_ip6(&w->addr, w->addrlen)) num = w->outnet->num_ip6; @@ -226,6 +228,7 @@ pick_outgoing_tcp(struct waiting_tcp* w, int s) #endif pi = &w->outnet->ip4_ifs[ub_random_max(w->outnet->rnd, num)]; log_assert(pi); + pend->pi = pi; if(addr_is_any(&pi->addr, pi->addrlen)) { /* binding to the ANY interface is for listening sockets */ return 1; @@ -567,7 +570,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w) if(s == -1) return 0; - if(!pick_outgoing_tcp(w, s)) + if(!pick_outgoing_tcp(pend, w, s)) return 0; fd_set_nonblock(s); @@ -731,6 +734,9 @@ use_free_buffer(struct outside_network* outnet) struct waiting_tcp* w; while(outnet->tcp_free && outnet->tcp_wait_first && !outnet->want_to_quit) { +#ifdef USE_DNSTAP + struct pending_tcp* pend_tcp = NULL; +#endif struct reuse_tcp* reuse = NULL; w = outnet->tcp_wait_first; outnet->tcp_wait_first = w->next_waiting; @@ -742,6 +748,9 @@ use_free_buffer(struct outside_network* outnet) if(reuse) { log_reuse_tcp(VERB_CLIENT, "use free buffer for waiting tcp: " "found reuse", reuse); +#ifdef USE_DNSTAP + pend_tcp = reuse->pending; +#endif reuse_tcp_lru_touch(outnet, reuse); comm_timer_disable(w->timer); w->next_waiting = (void*)reuse->pending; @@ -768,8 +777,25 @@ use_free_buffer(struct outside_network* outnet) waiting_tcp_callback(w, NULL, NETEVENT_CLOSED, NULL); waiting_tcp_delete(w); +#ifdef USE_DNSTAP + w = NULL; +#endif } +#ifdef USE_DNSTAP + pend_tcp = pend; +#endif } +#ifdef USE_DNSTAP + if(outnet->dtenv && pend_tcp && w && w->sq && + (outnet->dtenv->log_resolver_query_messages || + outnet->dtenv->log_forwarder_query_messages)) { + sldns_buffer tmp; + sldns_buffer_init_frm_data(&tmp, w->pkt, w->pkt_len); + dt_msg_send_outside_query(outnet->dtenv, &w->sq->addr, + &pend_tcp->pi->addr, comm_tcp, w->sq->zone, + w->sq->zonelen, &tmp); + } +#endif } } @@ -1457,7 +1483,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, return NULL; } pc->cp = comm_point_create_udp(outnet->base, -1, - outnet->udp_buff, outnet_udp_cb, outnet); + outnet->udp_buff, outnet_udp_cb, outnet, NULL); if(!pc->cp) { log_err("malloc failed"); free(pc); @@ -1932,11 +1958,21 @@ randomize_and_send_udp(struct pending* pend, sldns_buffer* packet, int timeout) comm_timer_set(pend->timer, &tv); #ifdef USE_DNSTAP + /* + * sending src (local service)/dst (upstream) addresses over DNSTAP + * There are no chances to get the src (local service) addr if unbound + * is not configured with specific outgoing IP-addresses. So we will + * pass 0.0.0.0 (::) to argument for + * dt_msg_send_outside_query()/dt_msg_send_outside_response() calls. + */ if(outnet->dtenv && (outnet->dtenv->log_resolver_query_messages || - outnet->dtenv->log_forwarder_query_messages)) - dt_msg_send_outside_query(outnet->dtenv, &pend->addr, comm_udp, - pend->sq->zone, pend->sq->zonelen, packet); + outnet->dtenv->log_forwarder_query_messages)) { + log_addr(VERB_ALGO, "from local addr", &pend->pc->pif->addr, pend->pc->pif->addrlen); + log_addr(VERB_ALGO, "request to upstream", &pend->addr, pend->addrlen); + dt_msg_send_outside_query(outnet->dtenv, &pend->addr, &pend->pc->pif->addr, comm_udp, + pend->sq->zone, pend->sq->zonelen, packet); + } #endif return 1; } @@ -2168,6 +2204,9 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, w->write_wait_next = NULL; w->write_wait_queued = 0; w->error_count = 0; +#ifdef USE_DNSTAP + w->sq = NULL; +#endif if(pend) { /* we have a buffer available right now */ if(reuse) { @@ -2202,20 +2241,28 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, return NULL; } } +#ifdef USE_DNSTAP + if(sq->outnet->dtenv && + (sq->outnet->dtenv->log_resolver_query_messages || + sq->outnet->dtenv->log_forwarder_query_messages)) { + /* use w->pkt, because it has the ID value */ + sldns_buffer tmp; + sldns_buffer_init_frm_data(&tmp, w->pkt, w->pkt_len); + dt_msg_send_outside_query(sq->outnet->dtenv, &sq->addr, + &pend->pi->addr, comm_tcp, sq->zone, + sq->zonelen, &tmp); + } +#endif } else { /* queue up */ /* waiting for a buffer on the outside network buffer wait * list */ verbose(VERB_CLIENT, "pending_tcp_query: queue to wait"); +#ifdef USE_DNSTAP + w->sq = sq; +#endif outnet_add_tcp_waiting(sq->outnet, w); } -#ifdef USE_DNSTAP - if(sq->outnet->dtenv && - (sq->outnet->dtenv->log_resolver_query_messages || - sq->outnet->dtenv->log_forwarder_query_messages)) - dt_msg_send_outside_query(sq->outnet->dtenv, &sq->addr, - comm_tcp, sq->zone, sq->zonelen, packet); -#endif return w; } @@ -2721,6 +2768,11 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error, { struct serviced_query* sq = (struct serviced_query*)arg; struct comm_reply r2; +#ifdef USE_DNSTAP + struct waiting_tcp* w = (struct waiting_tcp*)sq->pending; + struct pending_tcp* pend_tcp = (struct pending_tcp*)w->next_waiting; + struct port_if* pi = pend_tcp->pi; +#endif sq->pending = NULL; /* removed after this callback */ if(error != NETEVENT_NOERROR) log_addr(VERB_QUERY, "tcp error for address", @@ -2729,12 +2781,19 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error, infra_update_tcp_works(sq->outnet->infra, &sq->addr, sq->addrlen, sq->zone, sq->zonelen); #ifdef USE_DNSTAP + /* + * sending src (local service)/dst (upstream) addresses over DNSTAP + */ if(error==NETEVENT_NOERROR && sq->outnet->dtenv && (sq->outnet->dtenv->log_resolver_response_messages || - sq->outnet->dtenv->log_forwarder_response_messages)) + sq->outnet->dtenv->log_forwarder_response_messages)) { + log_addr(VERB_ALGO, "response from upstream", &sq->addr, sq->addrlen); + log_addr(VERB_ALGO, "to local addr", &pi->addr, pi->addrlen); dt_msg_send_outside_response(sq->outnet->dtenv, &sq->addr, - c->type, sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen, - &sq->last_sent_time, sq->outnet->now_tv, c->buffer); + &pi->addr, c->type, sq->zone, sq->zonelen, sq->qbuf, + sq->qbuflen, &sq->last_sent_time, sq->outnet->now_tv, + c->buffer); + } #endif if(error==NETEVENT_NOERROR && sq->status == serviced_query_TCP_EDNS && (LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer)) == @@ -2888,6 +2947,10 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, struct serviced_query* sq = (struct serviced_query*)arg; struct outside_network* outnet = sq->outnet; struct timeval now = *sq->outnet->now_tv; +#ifdef USE_DNSTAP + struct pending* p = (struct pending*)sq->pending; + struct port_if* pi = p->pc->pif; +#endif sq->pending = NULL; /* removed after callback */ if(error == NETEVENT_TIMEOUT) { @@ -2925,12 +2988,18 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, return 0; } #ifdef USE_DNSTAP + /* + * sending src (local service)/dst (upstream) addresses over DNSTAP + */ if(error == NETEVENT_NOERROR && outnet->dtenv && (outnet->dtenv->log_resolver_response_messages || - outnet->dtenv->log_forwarder_response_messages)) - dt_msg_send_outside_response(outnet->dtenv, &sq->addr, c->type, - sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen, - &sq->last_sent_time, sq->outnet->now_tv, c->buffer); + outnet->dtenv->log_forwarder_response_messages)) { + log_addr(VERB_ALGO, "response from upstream", &sq->addr, sq->addrlen); + log_addr(VERB_ALGO, "to local addr", &pi->addr, pi->addrlen); + dt_msg_send_outside_response(outnet->dtenv, &sq->addr, &pi->addr, c->type, + sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen, + &sq->last_sent_time, sq->outnet->now_tv, c->buffer); + } #endif if( (sq->status == serviced_query_UDP_EDNS ||sq->status == serviced_query_UDP_EDNS_FRAG) @@ -3204,7 +3273,7 @@ outnet_comm_point_for_udp(struct outside_network* outnet, return NULL; } cp = comm_point_create_udp(outnet->base, fd, outnet->udp_buff, - cb, cb_arg); + cb, cb_arg, NULL); if(!cp) { log_err("malloc failure"); close(fd); diff --git a/services/outside_network.h b/services/outside_network.h index fe287af4f..233588d40 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -344,6 +344,8 @@ struct pending { struct pending_tcp { /** next in list of free tcp comm points, or NULL. */ struct pending_tcp* next_free; + /** port for of the outgoing interface that is used */ + struct port_if* pi; /** tcp comm point it was sent on (and reply must come back on). */ struct comm_point* c; /** the query being serviced, NULL if the pending_tcp is unused. */ @@ -408,6 +410,10 @@ struct waiting_tcp { char* tls_auth_name; /** the packet was involved in an error, to stop looping errors */ int error_count; +#ifdef USE_DNSTAP + /** serviced query pointer for dnstap to get logging info, if nonNULL*/ + struct serviced_query* sq; +#endif }; /** diff --git a/testcode/fake_event.c b/testcode/fake_event.c index b8166c45c..9508f3225 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1629,7 +1629,8 @@ int create_udp_sock(int ATTR_UNUSED(family), int ATTR_UNUSED(socktype), struct comm_point* comm_point_create_udp(struct comm_base *ATTR_UNUSED(base), int ATTR_UNUSED(fd), sldns_buffer* ATTR_UNUSED(buffer), comm_point_callback_type* ATTR_UNUSED(callback), - void* ATTR_UNUSED(callback_arg)) + void* ATTR_UNUSED(callback_arg), + struct unbound_socket* ATTR_UNUSED(socket)) { log_assert(0); return NULL; diff --git a/util/net_help.c b/util/net_help.c index 3b5527adf..bcc8d34bd 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -1609,5 +1609,4 @@ sock_close(int socket) { closesocket(socket); } - # endif /* USE_WINSOCK */ diff --git a/util/netevent.c b/util/netevent.c index d55458d6d..6ef84133b 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -51,6 +51,16 @@ #include "dnstap/dnstap.h" #include "dnscrypt/dnscrypt.h" #include "services/listen_dnsport.h" +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + #ifdef HAVE_OPENSSL_SSL_H #include #endif @@ -152,7 +162,7 @@ struct internal_signal { static struct comm_point* comm_point_create_tcp_handler( struct comm_base *base, struct comm_point* parent, size_t bufsize, struct sldns_buffer* spoolbuf, comm_point_callback_type* callback, - void* callback_arg); + void* callback_arg, struct unbound_socket* socket); /* -------- End of local definitions -------- */ @@ -408,7 +418,9 @@ static void p_ancil(const char* str, struct comm_reply* r) log_info("%s: unknown srctype %d", str, r->srctype); return; } + if(r->srctype == 6) { +#ifdef IPV6_PKTINFO char buf[1024]; if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr, buf, (socklen_t)sizeof(buf)) == 0) { @@ -416,6 +428,7 @@ static void p_ancil(const char* str, struct comm_reply* r) } buf[sizeof(buf)-1]=0; log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex); +#endif } else if(r->srctype == 4) { #ifdef IP_PKTINFO char buf1[1024], buf2[1024]; @@ -3193,7 +3206,7 @@ void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), struct comm_point* comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, - comm_point_callback_type* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -3232,6 +3245,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, c->inuse = 0; c->callback = callback; c->cb_arg = callback_arg; + c->socket = socket; evbits = UB_EV_READ | UB_EV_PERSIST; /* ub_event stuff */ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, @@ -3253,7 +3267,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, struct comm_point* comm_point_create_udp_ancil(struct comm_base *base, int fd, sldns_buffer* buffer, - comm_point_callback_type* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -3292,6 +3306,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd, #endif c->callback = callback; c->cb_arg = callback_arg; + c->socket = socket; evbits = UB_EV_READ | UB_EV_PERSIST; /* ub_event stuff */ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, @@ -3314,7 +3329,7 @@ static struct comm_point* comm_point_create_tcp_handler(struct comm_base *base, struct comm_point* parent, size_t bufsize, struct sldns_buffer* spoolbuf, comm_point_callback_type* callback, - void* callback_arg) + void* callback_arg, struct unbound_socket* socket) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -3370,6 +3385,7 @@ comm_point_create_tcp_handler(struct comm_base *base, c->repinfo.c = c; c->callback = callback; c->cb_arg = callback_arg; + c->socket = socket; if(spoolbuf) { c->tcp_req_info = tcp_req_info_create(spoolbuf); if(!c->tcp_req_info) { @@ -3409,7 +3425,8 @@ static struct comm_point* comm_point_create_http_handler(struct comm_base *base, struct comm_point* parent, size_t bufsize, int harden_large_queries, uint32_t http_max_streams, char* http_endpoint, - comm_point_callback_type* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg, + struct unbound_socket* socket) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -3463,6 +3480,7 @@ comm_point_create_http_handler(struct comm_base *base, c->repinfo.c = c; c->callback = callback; c->cb_arg = callback_arg; + c->socket = socket; c->http_min_version = http_version_2; c->http2_stream_max_qbuffer_size = bufsize; @@ -3527,7 +3545,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, uint32_t http_max_streams, char* http_endpoint, struct tcl_list* tcp_conn_limit, size_t bufsize, struct sldns_buffer* spoolbuf, enum listen_type port_type, - comm_point_callback_type* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -3577,6 +3595,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, #endif c->callback = NULL; c->cb_arg = NULL; + c->socket = socket; evbits = UB_EV_READ | UB_EV_PERSIST; /* ub_event stuff */ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, @@ -3598,12 +3617,12 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, port_type == listen_type_ssl || port_type == listen_type_tcp_dnscrypt) { c->tcp_handlers[i] = comm_point_create_tcp_handler(base, - c, bufsize, spoolbuf, callback, callback_arg); + c, bufsize, spoolbuf, callback, callback_arg, socket); } else if(port_type == listen_type_http) { c->tcp_handlers[i] = comm_point_create_http_handler( base, c, bufsize, harden_large_queries, http_max_streams, http_endpoint, - callback, callback_arg); + callback, callback_arg, socket); } else { log_err("could not create tcp handler, unknown listen " @@ -3979,20 +3998,26 @@ comm_point_send_reply(struct comm_reply *repinfo) comm_point_send_udp_msg(repinfo->c, buffer, (struct sockaddr*)&repinfo->addr, repinfo->addrlen, 0); #ifdef USE_DNSTAP - if(repinfo->c->dtenv != NULL && - repinfo->c->dtenv->log_client_response_messages) - dt_msg_send_client_response(repinfo->c->dtenv, - &repinfo->addr, repinfo->c->type, repinfo->c->buffer); + /* + * sending src (client)/dst (local service) addresses over DNSTAP from udp callback + */ + if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) { + log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); + log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen); + dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->buffer); + } #endif } else { #ifdef USE_DNSTAP - if(repinfo->c->tcp_parent->dtenv != NULL && - repinfo->c->tcp_parent->dtenv->log_client_response_messages) - dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, - &repinfo->addr, repinfo->c->type, - ( repinfo->c->tcp_req_info - ? repinfo->c->tcp_req_info->spool_buffer - : repinfo->c->buffer )); + /* + * sending src (client)/dst (local service) addresses over DNSTAP from TCP callback + */ + if(repinfo->c->tcp_parent->dtenv != NULL && repinfo->c->tcp_parent->dtenv->log_client_response_messages) { + log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); + log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen); + dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, + ( repinfo->c->tcp_req_info? repinfo->c->tcp_req_info->spool_buffer: repinfo->c->buffer )); + } #endif if(repinfo->c->tcp_req_info) { tcp_req_info_send_reply(repinfo->c->tcp_req_info); diff --git a/util/netevent.h b/util/netevent.h index 4a2aa1677..c79f99b3e 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -70,6 +70,7 @@ struct comm_point; struct comm_reply; struct tcl_list; struct ub_event_base; +struct unbound_socket; struct mesh_state; struct mesh_area; @@ -169,6 +170,8 @@ struct comm_point { /** if the event is added or not */ int event_added; + struct unbound_socket* socket; + /** file descriptor for communication point */ int fd; @@ -495,12 +498,13 @@ struct ub_event_base* comm_base_internal(struct comm_base* b); * @param buffer: shared buffer by UDP sockets from this thread. * @param callback: callback function pointer. * @param callback_arg: will be passed to your callback function. + * @param socket: and opened socket properties will be passed to your callback function. * @return: returns the allocated communication point. NULL on error. * Sets timeout to NULL. Turns off TCP options. */ struct comm_point* comm_point_create_udp(struct comm_base* base, int fd, struct sldns_buffer* buffer, - comm_point_callback_type* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket); /** * Create an UDP with ancillary data comm point. Calls malloc. @@ -511,12 +515,13 @@ struct comm_point* comm_point_create_udp(struct comm_base* base, * @param buffer: shared buffer by UDP sockets from this thread. * @param callback: callback function pointer. * @param callback_arg: will be passed to your callback function. + * @param socket: and opened socket properties will be passed to your callback function. * @return: returns the allocated communication point. NULL on error. * Sets timeout to NULL. Turns off TCP options. */ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, int fd, struct sldns_buffer* buffer, - comm_point_callback_type* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket); /** * Create a TCP listener comm point. Calls malloc. @@ -539,6 +544,7 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, * to select handler type to use. * @param callback: callback function pointer for TCP handlers. * @param callback_arg: will be passed to your callback function. + * @param socket: and opened socket properties will be passed to your callback function. * @return: returns the TCP listener commpoint. You can find the * TCP handlers in the array inside the listener commpoint. * returns NULL on error. @@ -550,7 +556,7 @@ struct comm_point* comm_point_create_tcp(struct comm_base* base, struct tcl_list* tcp_conn_limit, size_t bufsize, struct sldns_buffer* spoolbuf, enum listen_type port_type, - comm_point_callback_type* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket); /** * Create an outgoing TCP commpoint. No file descriptor is opened, left at -1.