mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
PROXYv2 downstream support (#760)
This commit is contained in:
parent
7d96a7e3fe
commit
c4e51a4cfe
@ -130,7 +130,7 @@ util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
|
||||
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
|
||||
util/rtt.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
|
||||
util/storage/lruhash.c util/storage/slabhash.c util/tcp_conn_limit.c \
|
||||
util/timehist.c util/tube.c \
|
||||
util/timehist.c util/tube.c util/proxy_protocol.c \
|
||||
util/ub_event.c util/ub_event_pluggable.c util/winsock_event.c \
|
||||
validator/autotrust.c validator/val_anchor.c validator/validator.c \
|
||||
validator/val_kcache.c validator/val_kentry.c validator/val_neg.c \
|
||||
@ -148,7 +148,7 @@ outbound_list.lo alloc.lo config_file.lo configlexer.lo configparser.lo \
|
||||
fptr_wlist.lo edns.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
|
||||
random.lo rbtree.lo regional.lo rtt.lo dnstree.lo lookup3.lo lruhash.lo \
|
||||
slabhash.lo tcp_conn_limit.lo timehist.lo tube.lo winsock_event.lo \
|
||||
autotrust.lo val_anchor.lo rpz.lo \
|
||||
autotrust.lo val_anchor.lo rpz.lo proxy_protocol.lo \
|
||||
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
|
||||
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo \
|
||||
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
|
||||
@ -984,6 +984,8 @@ netevent.lo netevent.o: $(srcdir)/util/netevent.c config.h $(srcdir)/util/neteve
|
||||
$(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h $(srcdir)/services/authzone.h $(srcdir)/daemon/stats.h \
|
||||
$(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h $(srcdir)/respip/respip.h $(srcdir)/sldns/str2wire.h \
|
||||
$(srcdir)/dnstap/dnstap.h $(srcdir)/services/listen_dnsport.h
|
||||
proxy_protocol.lo proxy_protocol.o: $(srcdir)/util/proxy_protocol.c config.h \
|
||||
$(srcdir)/util/proxy_protocol.h $(srcdir)/sldns/sbuffer.h
|
||||
net_help.lo net_help.o: $(srcdir)/util/net_help.c config.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/module.h \
|
||||
$(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \
|
||||
@ -1512,7 +1514,7 @@ asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libu
|
||||
$(srcdir)/services/modstack.h $(srcdir)/libunbound/unbound-event.h $(srcdir)/util/data/packed_rrset.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/sldns/rrdef.h
|
||||
streamtcp.lo streamtcp.o: $(srcdir)/testcode/streamtcp.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/util/net_help.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/msgparse.h \
|
||||
$(srcdir)/util/net_help.h $(srcdir)/util/proxy_protocol.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/msgparse.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h \
|
||||
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/dname.h $(srcdir)/sldns/sbuffer.h \
|
||||
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
|
||||
|
@ -494,8 +494,8 @@ int remote_accept_callback(struct comm_point* c, void* arg, int err,
|
||||
n->c->do_not_close = 0;
|
||||
comm_point_stop_listening(n->c);
|
||||
comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT);
|
||||
memcpy(&n->c->repinfo.addr, &addr, addrlen);
|
||||
n->c->repinfo.addrlen = addrlen;
|
||||
memcpy(&n->c->repinfo.remote_addr, &addr, addrlen);
|
||||
n->c->repinfo.remote_addrlen = addrlen;
|
||||
if(rc->use_cert) {
|
||||
n->shake_state = rc_hs_read;
|
||||
n->ssl = SSL_new(rc->ctx);
|
||||
@ -3304,7 +3304,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s,
|
||||
if(r == 0)
|
||||
log_err("remote control connection closed prematurely");
|
||||
log_addr(VERB_OPS, "failed connection from",
|
||||
&s->c->repinfo.addr, s->c->repinfo.addrlen);
|
||||
&s->c->repinfo.remote_addr, s->c->repinfo.remote_addrlen);
|
||||
log_crypto_err("remote control failed ssl");
|
||||
clean_point(rc, s);
|
||||
}
|
||||
|
@ -521,7 +521,7 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
|
||||
stats->qhttps++;
|
||||
}
|
||||
}
|
||||
if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
|
||||
if(repinfo && addr_is_ip6(&repinfo->remote_addr, repinfo->remote_addrlen))
|
||||
stats->qipv6++;
|
||||
if( (flags&BIT_QR) )
|
||||
stats->qbit_QR++;
|
||||
|
139
daemon/worker.c
139
daemon/worker.c
@ -547,7 +547,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
static int
|
||||
apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, struct reply_info* rep,
|
||||
struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** encode_repp, struct auth_zones* az)
|
||||
{
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
@ -574,7 +575,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
if(actinfo.addrinfo) {
|
||||
respip_inform_print(&actinfo, qinfo->qname,
|
||||
qinfo->qtype, qinfo->qclass, qinfo->local_alias,
|
||||
repinfo);
|
||||
addr, addrlen);
|
||||
|
||||
if(worker->stats.extended && actinfo.rpz_used) {
|
||||
if(actinfo.rpz_disabled)
|
||||
@ -703,7 +704,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
|
||||
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
|
||||
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
|
||||
repinfo, alias_rrset,
|
||||
&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
|
||||
&encode_rep, worker->env.auth_zones)) {
|
||||
goto bail_out;
|
||||
} else if(partial_rep &&
|
||||
@ -991,12 +992,14 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
|
||||
* @param w: worker
|
||||
* @param qinfo: query info. Pointer into packet buffer.
|
||||
* @param edns: edns info from query.
|
||||
* @param repinfo: reply info with source address.
|
||||
* @param addr: client address.
|
||||
* @param addrlen: client address length.
|
||||
* @param pkt: packet buffer.
|
||||
*/
|
||||
static void
|
||||
answer_notify(struct worker* w, struct query_info* qinfo,
|
||||
struct edns_data* edns, sldns_buffer* pkt, struct comm_reply* repinfo)
|
||||
struct edns_data* edns, sldns_buffer* pkt,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
{
|
||||
int refused = 0;
|
||||
int rcode = LDNS_RCODE_NOERROR;
|
||||
@ -1005,8 +1008,8 @@ answer_notify(struct worker* w, struct query_info* qinfo,
|
||||
if(!w->env.auth_zones) return;
|
||||
has_serial = auth_zone_parse_notify_serial(pkt, &serial);
|
||||
if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname,
|
||||
qinfo->qname_len, qinfo->qclass, &repinfo->addr,
|
||||
repinfo->addrlen, has_serial, serial, &refused)) {
|
||||
qinfo->qname_len, qinfo->qclass, addr,
|
||||
addrlen, has_serial, serial, &refused)) {
|
||||
rcode = LDNS_RCODE_NOERROR;
|
||||
} else {
|
||||
if(refused)
|
||||
@ -1031,7 +1034,7 @@ answer_notify(struct worker* w, struct query_info* qinfo,
|
||||
"servfail for NOTIFY %sfor %s from", sr, zname);
|
||||
else snprintf(buf, sizeof(buf),
|
||||
"received NOTIFY %sfor %s from", sr, zname);
|
||||
log_addr(VERB_DETAIL, buf, &repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_DETAIL, buf, addr, addrlen);
|
||||
}
|
||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
@ -1051,8 +1054,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
{
|
||||
if(acl == deny) {
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
log_acl_action("dropped", &repinfo->addr,
|
||||
repinfo->addrlen, acl, acladdr);
|
||||
log_acl_action("dropped", &repinfo->client_addr,
|
||||
repinfo->client_addrlen, acl, acladdr);
|
||||
log_buf(VERB_ALGO, "dropped", c->buffer);
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@ -1063,8 +1066,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
size_t opt_rr_mark;
|
||||
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
log_acl_action("refused", &repinfo->addr,
|
||||
repinfo->addrlen, acl, acladdr);
|
||||
log_acl_action("refused", &repinfo->client_addr,
|
||||
repinfo->client_addrlen, acl, acladdr);
|
||||
log_buf(VERB_ALGO, "refuse", c->buffer);
|
||||
}
|
||||
|
||||
@ -1224,12 +1227,24 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
}
|
||||
|
||||
static int
|
||||
deny_refuse_all(struct comm_point* c, enum acl_access acl,
|
||||
deny_refuse_all(struct comm_point* c, enum acl_access* acl,
|
||||
struct worker* worker, struct comm_reply* repinfo,
|
||||
struct acl_addr* acladdr, int ede)
|
||||
struct acl_addr** acladdr, int ede, int check_proxy)
|
||||
{
|
||||
return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo,
|
||||
acladdr, ede);
|
||||
if(check_proxy) {
|
||||
*acladdr = acl_addr_lookup(worker->daemon->acl,
|
||||
&repinfo->remote_addr, repinfo->remote_addrlen);
|
||||
} else {
|
||||
*acladdr = acl_addr_lookup(worker->daemon->acl,
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
}
|
||||
/* If there is no ACL based on client IP use the interface ACL. */
|
||||
if(!(*acladdr) && c->socket) {
|
||||
*acladdr = c->socket->acl;
|
||||
}
|
||||
*acl = acl_get_control(*acladdr);
|
||||
return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo,
|
||||
*acladdr, ede);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1323,29 +1338,30 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
* 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, "request from client", &repinfo->client_addr, repinfo->client_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);
|
||||
dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
|
||||
}
|
||||
#endif
|
||||
acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr,
|
||||
repinfo->addrlen);
|
||||
/* If there is no ACL based on client IP use the interface ACL. */
|
||||
if(!acladdr && c->socket) {
|
||||
acladdr = c->socket->acl;
|
||||
}
|
||||
acl = acl_get_control(acladdr);
|
||||
|
||||
if((ret=deny_refuse_all(c, acl, worker, repinfo, acladdr,
|
||||
worker->env.cfg->ede)) != -1)
|
||||
{
|
||||
/* Check deny/refuse ACLs */
|
||||
if(repinfo->is_proxied) {
|
||||
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
|
||||
worker->env.cfg->ede, 1)) != -1) {
|
||||
if(ret == 1)
|
||||
goto send_reply;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
|
||||
worker->env.cfg->ede, 0)) != -1) {
|
||||
if(ret == 1)
|
||||
goto send_reply;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if((ret=worker_check_request(c->buffer, worker)) != 0) {
|
||||
verbose(VERB_ALGO, "worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
|
||||
if(ret != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
|
||||
@ -1357,20 +1373,24 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
|
||||
worker->stats.num_queries++;
|
||||
|
||||
/* check if this query should be dropped based on source ip rate limiting */
|
||||
if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo,
|
||||
/* check if this query should be dropped based on source ip rate limiting
|
||||
* NOTE: we always check the repinfo->client_address. IP ratelimiting is
|
||||
* implicitly disabled for proxies. */
|
||||
if(!infra_ip_ratelimit_inc(worker->env.infra_cache,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
*worker->env.now,
|
||||
worker->env.cfg->ip_ratelimit_backoff, c->buffer)) {
|
||||
/* See if we are passed through with slip factor */
|
||||
if(worker->env.cfg->ip_ratelimit_factor != 0 &&
|
||||
ub_random_max(worker->env.rnd,
|
||||
worker->env.cfg->ip_ratelimit_factor) == 0) {
|
||||
|
||||
char addrbuf[128];
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen,
|
||||
addrbuf, sizeof(addrbuf));
|
||||
verbose(VERB_QUERY, "ip_ratelimit allowed through for ip address %s because of slip in ip_ratelimit_factor",
|
||||
addrbuf);
|
||||
addr_to_str(&repinfo->client_addr,
|
||||
repinfo->client_addrlen, addrbuf,
|
||||
sizeof(addrbuf));
|
||||
verbose(VERB_QUERY, "ip_ratelimit allowed through for "
|
||||
"ip address %s because of slip in "
|
||||
"ip_ratelimit_factor", addrbuf);
|
||||
} else {
|
||||
worker->stats.num_queries_ip_ratelimited++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
@ -1381,7 +1401,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
/* see if query is in the cache */
|
||||
if(!query_info_parse(&qinfo, c->buffer)) {
|
||||
verbose(VERB_ALGO, "worker parse request: formerror.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
@ -1395,13 +1416,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
if(worker->env.cfg->log_queries) {
|
||||
char ip[128];
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
|
||||
addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip));
|
||||
log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
|
||||
}
|
||||
if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
|
||||
qinfo.qtype == LDNS_RR_TYPE_IXFR) {
|
||||
verbose(VERB_ALGO, "worker request: refused zone transfer.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
@ -1418,7 +1440,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
qinfo.qtype == LDNS_RR_TYPE_MAILB ||
|
||||
(qinfo.qtype >= 128 && qinfo.qtype <= 248)) {
|
||||
verbose(VERB_ALGO, "worker request: formerror for meta-type.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
@ -1436,7 +1459,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
worker->scratchpad)) != 0) {
|
||||
struct edns_data reply_edns;
|
||||
verbose(VERB_ALGO, "worker parse edns: formerror.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
memset(&reply_edns, 0, sizeof(reply_edns));
|
||||
reply_edns.edns_present = 1;
|
||||
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
@ -1458,7 +1482,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
edns.opt_list_inplace_cb_out = NULL;
|
||||
edns.padding_block_size = 0;
|
||||
verbose(VERB_ALGO, "query with bad edns version.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), NULL);
|
||||
@ -1472,7 +1497,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
worker->daemon->cfg->harden_short_bufsize) {
|
||||
verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
|
||||
(int)edns.udp_size);
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
edns.udp_size = NORMAL_UDP_SIZE;
|
||||
}
|
||||
}
|
||||
@ -1481,12 +1507,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_QUERY,
|
||||
"worker request: max UDP reply size modified"
|
||||
" (%d to max-udp-size)", (int)edns.udp_size);
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
edns.udp_size = worker->daemon->cfg->max_udp_size;
|
||||
}
|
||||
if(edns.udp_size < LDNS_HEADER_SIZE) {
|
||||
verbose(VERB_ALGO, "worker request: edns is too small.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen);
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
@ -1510,7 +1538,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
|
||||
LDNS_PACKET_NOTIFY) {
|
||||
answer_notify(worker, &qinfo, &edns, c->buffer, repinfo);
|
||||
answer_notify(worker, &qinfo, &edns, c->buffer,
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
regional_free_all(worker->scratchpad);
|
||||
goto send_reply;
|
||||
}
|
||||
@ -1586,7 +1615,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
|
||||
regional_free_all(worker->scratchpad);
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->addr, repinfo->addrlen);
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
|
||||
goto send_reply;
|
||||
}
|
||||
@ -1726,9 +1755,9 @@ lookup_cache:
|
||||
if(verbosity >= VERB_CLIENT) {
|
||||
if(c->type == comm_udp)
|
||||
log_addr(VERB_CLIENT, "udp request from",
|
||||
&repinfo->addr, repinfo->addrlen);
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
else log_addr(VERB_CLIENT, "tcp request from",
|
||||
&repinfo->addr, repinfo->addrlen);
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
}
|
||||
|
||||
/* grab a work request structure for this new request */
|
||||
@ -1760,8 +1789,8 @@ send_reply_rc:
|
||||
*/
|
||||
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);
|
||||
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
|
||||
dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
|
||||
}
|
||||
#endif
|
||||
if(worker->env.cfg->log_replies)
|
||||
@ -1773,10 +1802,12 @@ send_reply_rc:
|
||||
/* log original qname, before the local alias was
|
||||
* used to resolve that CNAME to something else */
|
||||
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
|
||||
log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen,
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer);
|
||||
} else {
|
||||
log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen,
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer);
|
||||
}
|
||||
}
|
||||
|
@ -902,6 +902,10 @@ server:
|
||||
# Disable TLS for DNS-over-HTTP downstream service.
|
||||
# http-notls-downstream: no
|
||||
|
||||
# The interfaces that use these listed port numbers will support and
|
||||
# expect PROXYv2. For UDP and TCP/TLS interfaces.
|
||||
# proxy-protocol-port: portno for each of the port numbers.
|
||||
|
||||
# DNS64 prefix. Must be specified when DNS64 is use.
|
||||
# Enable dns64 in module-config. Used to synthesize IPv6 from IPv4.
|
||||
# dns64-prefix: 64:ff9b::0/96
|
||||
|
@ -656,6 +656,17 @@ Ignored if the option is not available. Default is yes.
|
||||
Disable use of TLS for the downstream DNS-over-HTTP connections. Useful for
|
||||
local back end servers. Default is no.
|
||||
.TP
|
||||
.B proxy\-protocol\-port: \fI<portnr>
|
||||
List port numbers as proxy\-protocol\-port, and when interfaces are defined,
|
||||
eg. with the @port suffix, as this port number, they support and expect PROXYv2.
|
||||
In this case the proxy address will only be used for the network communication
|
||||
and initial ACL (check if the proxy itself is denied/refused by configuration).
|
||||
The proxied address (if any) will then be used as the true client address and
|
||||
will be used where applicable for logging, ACL, DNSTAP, RPZ and IP ratelimiting.
|
||||
PROXYv2 is supported for UDP and TCP/TLS listening interfaces.
|
||||
There is no support for PROXYv2 on a DoH or DNSCrypt listening interface.
|
||||
Can list multiple, each on a new statement.
|
||||
.TP
|
||||
.B use\-systemd: \fI<yes or no>
|
||||
Enable or disable systemd socket activation.
|
||||
Default is no.
|
||||
|
@ -765,7 +765,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
}
|
||||
else if(qstate->mesh_info->reply_list) {
|
||||
subnet_option_from_ss(
|
||||
&qstate->mesh_info->reply_list->query_reply.addr,
|
||||
&qstate->mesh_info->reply_list->query_reply.client_addr,
|
||||
&sq->ecs_client_in, qstate->env->cfg);
|
||||
}
|
||||
|
||||
|
@ -596,15 +596,17 @@ errinf_reply(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
|
||||
return;
|
||||
if((qstate->reply && qstate->reply->addrlen != 0) ||
|
||||
(iq->fail_reply && iq->fail_reply->addrlen != 0)) {
|
||||
if((qstate->reply && qstate->reply->remote_addrlen != 0) ||
|
||||
(iq->fail_reply && iq->fail_reply->remote_addrlen != 0)) {
|
||||
char from[256], frm[512];
|
||||
if(qstate->reply && qstate->reply->addrlen != 0)
|
||||
addr_to_str(&qstate->reply->addr, qstate->reply->addrlen,
|
||||
from, sizeof(from));
|
||||
if(qstate->reply && qstate->reply->remote_addrlen != 0)
|
||||
addr_to_str(&qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen, from,
|
||||
sizeof(from));
|
||||
else
|
||||
addr_to_str(&iq->fail_reply->addr, iq->fail_reply->addrlen,
|
||||
from, sizeof(from));
|
||||
addr_to_str(&iq->fail_reply->remote_addr,
|
||||
iq->fail_reply->remote_addrlen, from,
|
||||
sizeof(from));
|
||||
snprintf(frm, sizeof(frm), "from %s", from);
|
||||
errinf(qstate, frm);
|
||||
}
|
||||
@ -2896,8 +2898,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* use dnssec-lame-bypass if it needs to query there.*/
|
||||
if(qstate->reply) {
|
||||
struct delegpt_addr* a = delegpt_find_addr(
|
||||
iq->dp, &qstate->reply->addr,
|
||||
qstate->reply->addrlen);
|
||||
iq->dp, &qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen);
|
||||
if(a) a->dnsseclame = 1;
|
||||
}
|
||||
/* test the answer is from the zone we expected,
|
||||
@ -2994,8 +2996,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->num_target_queries = 0;
|
||||
if(qstate->reply)
|
||||
sock_list_insert(&qstate->reply_origin,
|
||||
&qstate->reply->addr, qstate->reply->addrlen,
|
||||
qstate->region);
|
||||
&qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen, qstate->region);
|
||||
if(iq->minimisation_state != DONOT_MINIMISE_STATE
|
||||
&& !(iq->chase_flags & BIT_RD)) {
|
||||
if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
|
||||
@ -3251,8 +3253,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->num_target_queries = 0;
|
||||
if(qstate->reply)
|
||||
sock_list_insert(&qstate->reply_origin,
|
||||
&qstate->reply->addr, qstate->reply->addrlen,
|
||||
qstate->region);
|
||||
&qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen, qstate->region);
|
||||
verbose(VERB_ALGO, "cleared outbound list for query restart");
|
||||
/* go to INIT_REQUEST_STATE for new qname. */
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
@ -3267,7 +3269,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* need addr for lameness cache, but we may have
|
||||
* gotten this from cache, so test to be sure */
|
||||
if(!infra_set_lame(qstate->env->infra_cache,
|
||||
&qstate->reply->addr, qstate->reply->addrlen,
|
||||
&qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen,
|
||||
iq->dp->name, iq->dp->namelen,
|
||||
*qstate->env->now, dnsseclame, 0,
|
||||
iq->qchase.qtype))
|
||||
@ -3285,7 +3288,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* gotten this from cache, so test to be sure */
|
||||
verbose(VERB_DETAIL, "mark as REC_LAME");
|
||||
if(!infra_set_lame(qstate->env->infra_cache,
|
||||
&qstate->reply->addr, qstate->reply->addrlen,
|
||||
&qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen,
|
||||
iq->dp->name, iq->dp->namelen,
|
||||
*qstate->env->now, 0, 1, iq->qchase.qtype))
|
||||
log_err("mark host lame: out of memory");
|
||||
@ -4017,7 +4021,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
goto handle_it;
|
||||
log_query_info(VERB_DETAIL, "response for", &qstate->qinfo);
|
||||
log_name_addr(VERB_DETAIL, "reply from", iq->dp->name,
|
||||
&qstate->reply->addr, qstate->reply->addrlen);
|
||||
&qstate->reply->remote_addr, qstate->reply->remote_addrlen);
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
|
||||
iq->response->rep);
|
||||
|
@ -609,9 +609,9 @@ struct mesh_reply {
|
||||
struct comm_reply query_reply;
|
||||
};
|
||||
|
||||
%rename(_addr) comm_reply::addr;
|
||||
%rename(_addr) comm_reply::client_addr;
|
||||
struct comm_reply {
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr_storage client_addr;
|
||||
};
|
||||
|
||||
%extend comm_reply {
|
||||
|
@ -172,14 +172,14 @@ int createResponse(struct module_qstate* qstate, sldns_buffer* pkt)
|
||||
}
|
||||
|
||||
|
||||
/* Convert reply->addr to string */
|
||||
/* Convert reply->client_addr to string */
|
||||
void reply_addr2str(struct comm_reply* reply, char* dest, int maxlen)
|
||||
{
|
||||
int af = (int)((struct sockaddr_in*) &(reply->addr))->sin_family;
|
||||
void* sinaddr = &((struct sockaddr_in*) &(reply->addr))->sin_addr;
|
||||
int af = (int)((struct sockaddr_in*) &(reply->client_addr))->sin_family;
|
||||
void* sinaddr = &((struct sockaddr_in*) &(reply->client_addr))->sin_addr;
|
||||
|
||||
if(af == AF_INET6)
|
||||
sinaddr = &((struct sockaddr_in6*)&(reply->addr))->sin6_addr;
|
||||
sinaddr = &((struct sockaddr_in6*)&(reply->client_addr))->sin6_addr;
|
||||
dest[0] = 0;
|
||||
if (inet_ntop(af, sinaddr, dest, (socklen_t)maxlen) == 0)
|
||||
return;
|
||||
|
@ -1290,7 +1290,7 @@ respip_set_is_empty(const struct respip_set* set)
|
||||
void
|
||||
respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
|
||||
uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias,
|
||||
struct comm_reply* repinfo)
|
||||
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
{
|
||||
char srcip[128], respip[128], txt[512];
|
||||
unsigned port;
|
||||
@ -1300,10 +1300,10 @@ respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
|
||||
|
||||
if(local_alias)
|
||||
qname = local_alias->rrset->rk.dname;
|
||||
port = (unsigned)((repinfo->addr.ss_family == AF_INET) ?
|
||||
ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port) :
|
||||
ntohs(((struct sockaddr_in6*)&repinfo->addr)->sin6_port));
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen, srcip, sizeof(srcip));
|
||||
port = (unsigned)((addr->ss_family == AF_INET) ?
|
||||
ntohs(((struct sockaddr_in*)addr)->sin_port) :
|
||||
ntohs(((struct sockaddr_in6*)addr)->sin6_port));
|
||||
addr_to_str(addr, addrlen, srcip, sizeof(srcip));
|
||||
addr_to_str(&respip_addr->addr, respip_addr->addrlen,
|
||||
respip, sizeof(respip));
|
||||
if(respip_actinfo->rpz_log) {
|
||||
|
@ -251,11 +251,13 @@ int respip_set_is_empty(const struct respip_set* set);
|
||||
* @param local_alias: set to a local alias if the query matches an alias in
|
||||
* a local zone. In this case its owner name will be considered the actual
|
||||
* query name.
|
||||
* @param repinfo: reply info containing the client's source address and port.
|
||||
* @param addr: the client's source address and port.
|
||||
* @param addrlen: the client's source address length.
|
||||
*/
|
||||
void respip_inform_print(struct respip_action_info* respip_actinfo,
|
||||
uint8_t* qname, uint16_t qtype, uint16_t qclass,
|
||||
struct local_rrset* local_alias, struct comm_reply* repinfo);
|
||||
struct local_rrset* local_alias, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Find resp_addr in tree, create and add to tree if it does not exist.
|
||||
|
33
services/cache/infra.c
vendored
33
services/cache/infra.c
vendored
@ -834,14 +834,13 @@ static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
|
||||
|
||||
/** find data item in array for ip addresses */
|
||||
static struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, int wr)
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int wr)
|
||||
{
|
||||
struct ip_rate_key key;
|
||||
hashvalue_type h = hash_addr(&(repinfo->addr),
|
||||
repinfo->addrlen, 0);
|
||||
hashvalue_type h = hash_addr(addr, addrlen, 0);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.addr = repinfo->addr;
|
||||
key.addrlen = repinfo->addrlen;
|
||||
key.addr = *addr;
|
||||
key.addrlen = addrlen;
|
||||
key.entry.hash = h;
|
||||
return slabhash_lookup(infra->client_ip_rates, h, &key, wr);
|
||||
}
|
||||
@ -876,10 +875,9 @@ static void infra_create_ratedata(struct infra_cache* infra,
|
||||
|
||||
/** create rate data item for ip address */
|
||||
static void infra_ip_create_ratedata(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, time_t timenow)
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow)
|
||||
{
|
||||
hashvalue_type h = hash_addr(&(repinfo->addr),
|
||||
repinfo->addrlen, 0);
|
||||
hashvalue_type h = hash_addr(addr, addrlen, 0);
|
||||
struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
|
||||
struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d));
|
||||
if(!k || !d) {
|
||||
@ -887,8 +885,8 @@ static void infra_ip_create_ratedata(struct infra_cache* infra,
|
||||
free(d);
|
||||
return; /* alloc failure */
|
||||
}
|
||||
k->addr = repinfo->addr;
|
||||
k->addrlen = repinfo->addrlen;
|
||||
k->addr = *addr;
|
||||
k->addrlen = addrlen;
|
||||
lock_rw_init(&k->entry.lock);
|
||||
k->entry.hash = h;
|
||||
k->entry.key = k;
|
||||
@ -985,8 +983,8 @@ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
|
||||
sldns_wire2str_class_buf(qinfo->qclass, cs, sizeof(cs));
|
||||
ip[0]=0;
|
||||
if(replylist) {
|
||||
addr_to_str((struct sockaddr_storage *)&replylist->addr,
|
||||
replylist->addrlen, ip, sizeof(ip));
|
||||
addr_to_str((struct sockaddr_storage *)&replylist->remote_addr,
|
||||
replylist->remote_addrlen, ip, sizeof(ip));
|
||||
verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s from %s", buf, lim, qnm, cs, ts, ip);
|
||||
} else {
|
||||
verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s", buf, lim, qnm, cs, ts);
|
||||
@ -1054,8 +1052,8 @@ infra_get_mem(struct infra_cache* infra)
|
||||
}
|
||||
|
||||
int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, time_t timenow, int backoff,
|
||||
struct sldns_buffer* buffer)
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
|
||||
int backoff, struct sldns_buffer* buffer)
|
||||
{
|
||||
int max;
|
||||
struct lruhash_entry* entry;
|
||||
@ -1065,7 +1063,7 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
return 1;
|
||||
}
|
||||
/* find or insert ratedata */
|
||||
entry = infra_find_ip_ratedata(infra, repinfo, 1);
|
||||
entry = infra_find_ip_ratedata(infra, addr, addrlen, 1);
|
||||
if(entry) {
|
||||
int premax = infra_rate_max(entry->data, timenow, backoff);
|
||||
int* cur = infra_rate_give_second(entry->data, timenow);
|
||||
@ -1075,8 +1073,7 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
|
||||
if(premax <= infra_ip_ratelimit && max > infra_ip_ratelimit) {
|
||||
char client_ip[128], qnm[LDNS_MAX_DOMAINLEN+1+12+12];
|
||||
addr_to_str((struct sockaddr_storage *)&repinfo->addr,
|
||||
repinfo->addrlen, client_ip, sizeof(client_ip));
|
||||
addr_to_str(addr, addrlen, client_ip, sizeof(client_ip));
|
||||
qnm[0]=0;
|
||||
if(sldns_buffer_limit(buffer)>LDNS_HEADER_SIZE &&
|
||||
LDNS_QDCOUNT(sldns_buffer_begin(buffer))!=0) {
|
||||
@ -1101,6 +1098,6 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
}
|
||||
|
||||
/* create */
|
||||
infra_ip_create_ratedata(infra, repinfo, timenow);
|
||||
infra_ip_create_ratedata(infra, addr, addrlen, timenow);
|
||||
return 1;
|
||||
}
|
||||
|
7
services/cache/infra.h
vendored
7
services/cache/infra.h
vendored
@ -416,15 +416,16 @@ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
|
||||
/** Update query ratelimit hash and decide
|
||||
* whether or not a query should be dropped.
|
||||
* @param infra: infra cache
|
||||
* @param repinfo: information about client
|
||||
* @param addr: client address
|
||||
* @param addrlen: client address length
|
||||
* @param timenow: what time it is now.
|
||||
* @param backoff: if backoff is enabled.
|
||||
* @param buffer: with query for logging.
|
||||
* @return 1 if it could be incremented. 0 if the increment overshot the
|
||||
* ratelimit and the query should be dropped. */
|
||||
int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, time_t timenow, int backoff,
|
||||
struct sldns_buffer* buffer);
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
|
||||
int backoff, struct sldns_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Get memory used by the infra cache.
|
||||
|
@ -1093,11 +1093,13 @@ 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 pp2_enabled: if PROXYv2 is enabled for this port.
|
||||
* @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, struct unbound_socket* ub_sock)
|
||||
port_insert(struct listen_port** list, int s, enum listen_type ftype,
|
||||
int pp2_enabled, struct unbound_socket* ub_sock)
|
||||
{
|
||||
struct listen_port* item = (struct listen_port*)malloc(
|
||||
sizeof(struct listen_port));
|
||||
@ -1106,6 +1108,7 @@ port_insert(struct listen_port** list, int s, enum listen_type ftype, struct unb
|
||||
item->next = *list;
|
||||
item->fd = s;
|
||||
item->ftype = ftype;
|
||||
item->pp2_enabled = pp2_enabled;
|
||||
item->socket = ub_sock;
|
||||
*list = item;
|
||||
return 1;
|
||||
@ -1201,6 +1204,7 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port,
|
||||
* @param ssl_port: ssl service port number
|
||||
* @param tls_additional_port: list of additional ssl service port numbers.
|
||||
* @param https_port: DoH service port number
|
||||
* @param proxy_protocol_port: list of PROXYv2 port numbers.
|
||||
* @param reuseport: try to set SO_REUSEPORT if nonNULL and true.
|
||||
* set to false on exit if reuseport failed due to no kernel support.
|
||||
* @param transparent: set IP_TRANSPARENT socket option.
|
||||
@ -1217,25 +1221,30 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
struct addrinfo *hints, const char* port, struct listen_port** list,
|
||||
size_t rcv, size_t snd, int ssl_port,
|
||||
struct config_strlist* tls_additional_port, int https_port,
|
||||
struct config_strlist* proxy_protocol_port,
|
||||
int* reuseport, int transparent, int tcp_mss, int freebind,
|
||||
int http2_nodelay, int use_systemd, int dnscrypt_port, int dscp)
|
||||
{
|
||||
int s, noip6=0;
|
||||
int is_https = if_is_https(ifname, port, https_port);
|
||||
int is_dnscrypt = if_is_dnscrypt(ifname, port, dnscrypt_port);
|
||||
int is_pp2 = if_is_pp2(ifname, port, proxy_protocol_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) ||
|
||||
(!strchr(ifname, '@') && atoi(port) == dnscrypt_port));
|
||||
#else
|
||||
int is_dnscrypt = 0;
|
||||
(void)dnscrypt_port;
|
||||
#endif
|
||||
|
||||
if(!do_udp && !do_tcp)
|
||||
return 0;
|
||||
|
||||
if(is_pp2) {
|
||||
if(is_dnscrypt) {
|
||||
fatal_exit("PROXYv2 and DNSCrypt combination not "
|
||||
"supported!");
|
||||
} else if(is_https) {
|
||||
fatal_exit("PROXYv2 and DoH combination not "
|
||||
"supported!");
|
||||
}
|
||||
}
|
||||
|
||||
if(do_auto) {
|
||||
ub_sock = calloc(1, sizeof(struct unbound_socket));
|
||||
if(!ub_sock)
|
||||
@ -1260,7 +1269,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
}
|
||||
if(!port_insert(list, s, is_dnscrypt
|
||||
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
|
||||
ub_sock)) {
|
||||
is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
@ -1283,7 +1292,8 @@ 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, ub_sock)) {
|
||||
?listen_type_udp_dnscrypt:listen_type_udp,
|
||||
is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
@ -1318,7 +1328,7 @@ 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, ub_sock)) {
|
||||
if(!port_insert(list, s, port_type, is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
@ -1407,14 +1417,16 @@ 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, ports->socket);
|
||||
front->udp_buff, ports->pp2_enabled, 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->socket);
|
||||
ports->ftype, ports->pp2_enabled, 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,
|
||||
@ -1422,7 +1434,8 @@ 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->socket);
|
||||
ports->ftype, ports->pp2_enabled, cb, cb_arg,
|
||||
ports->socket);
|
||||
if(ports->ftype == listen_type_http) {
|
||||
if(!sslctx && !http_notls) {
|
||||
log_warn("HTTPS port configured, but "
|
||||
@ -1448,7 +1461,8 @@ 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, ports->socket);
|
||||
front->udp_buff, ports->pp2_enabled, cb,
|
||||
cb_arg, ports->socket);
|
||||
}
|
||||
if(!cp) {
|
||||
log_err("can't create commpoint");
|
||||
@ -1783,7 +1797,9 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
&hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
cfg->https_port, reuseport, cfg->ip_transparent,
|
||||
cfg->https_port,
|
||||
cfg->proxy_protocol_port,
|
||||
reuseport, cfg->ip_transparent,
|
||||
cfg->tcp_mss, cfg->ip_freebind,
|
||||
cfg->http_nodelay, cfg->use_systemd,
|
||||
cfg->dnscrypt_port, cfg->ip_dscp)) {
|
||||
@ -1798,7 +1814,9 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
&hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
cfg->https_port, reuseport, cfg->ip_transparent,
|
||||
cfg->https_port,
|
||||
cfg->proxy_protocol_port,
|
||||
reuseport, cfg->ip_transparent,
|
||||
cfg->tcp_mss, cfg->ip_freebind,
|
||||
cfg->http_nodelay, cfg->use_systemd,
|
||||
cfg->dnscrypt_port, cfg->ip_dscp)) {
|
||||
@ -1816,7 +1834,8 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
&hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
cfg->https_port, reuseport, cfg->ip_transparent,
|
||||
cfg->https_port, cfg->proxy_protocol_port,
|
||||
reuseport, cfg->ip_transparent,
|
||||
cfg->tcp_mss, cfg->ip_freebind,
|
||||
cfg->http_nodelay, cfg->use_systemd,
|
||||
cfg->dnscrypt_port, cfg->ip_dscp)) {
|
||||
@ -1831,7 +1850,8 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
&hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
cfg->https_port, reuseport, cfg->ip_transparent,
|
||||
cfg->https_port, cfg->proxy_protocol_port,
|
||||
reuseport, cfg->ip_transparent,
|
||||
cfg->tcp_mss, cfg->ip_freebind,
|
||||
cfg->http_nodelay, cfg->use_systemd,
|
||||
cfg->dnscrypt_port, cfg->ip_dscp)) {
|
||||
@ -1848,7 +1868,8 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
do_tcp, &hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
cfg->https_port, reuseport, cfg->ip_transparent,
|
||||
cfg->https_port, cfg->proxy_protocol_port,
|
||||
reuseport, cfg->ip_transparent,
|
||||
cfg->tcp_mss, cfg->ip_freebind,
|
||||
cfg->http_nodelay, cfg->use_systemd,
|
||||
cfg->dnscrypt_port, cfg->ip_dscp)) {
|
||||
@ -1863,7 +1884,8 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
|
||||
do_tcp, &hints, portbuf, &list,
|
||||
cfg->so_rcvbuf, cfg->so_sndbuf,
|
||||
cfg->ssl_port, cfg->tls_additional_port,
|
||||
cfg->https_port, reuseport, cfg->ip_transparent,
|
||||
cfg->https_port, cfg->proxy_protocol_port,
|
||||
reuseport, cfg->ip_transparent,
|
||||
cfg->tcp_mss, cfg->ip_freebind,
|
||||
cfg->http_nodelay, cfg->use_systemd,
|
||||
cfg->dnscrypt_port, cfg->ip_dscp)) {
|
||||
|
@ -128,7 +128,10 @@ 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 */
|
||||
/** if the port should support PROXYv2 */
|
||||
int pp2_enabled;
|
||||
/** fill in unbound_socket structure for every opened socket at
|
||||
* Unbound startup */
|
||||
struct unbound_socket* socket;
|
||||
};
|
||||
|
||||
|
@ -1744,13 +1744,13 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
|
||||
/** print log information for an inform zone query */
|
||||
static void
|
||||
lz_inform_print(struct local_zone* z, struct query_info* qinfo,
|
||||
struct comm_reply* repinfo)
|
||||
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
{
|
||||
char ip[128], txt[512];
|
||||
char zname[LDNS_MAX_DOMAINLEN+1];
|
||||
uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
|
||||
uint16_t port = ntohs(((struct sockaddr_in*)addr)->sin_port);
|
||||
dname_str(z->name, zname);
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
|
||||
addr_to_str(addr, addrlen, ip, sizeof(ip));
|
||||
snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip,
|
||||
(unsigned)port);
|
||||
log_nametypeclass(NO_VERBOSE, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
|
||||
@ -1765,7 +1765,8 @@ lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
|
||||
struct local_zone_override* lzo;
|
||||
if(repinfo && override_tree) {
|
||||
lzo = (struct local_zone_override*)addr_tree_lookup(
|
||||
override_tree, &repinfo->addr, repinfo->addrlen);
|
||||
override_tree, &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(lzo && lzo->type) {
|
||||
verbose(VERB_ALGO, "local zone override to type %s",
|
||||
local_zone_type2str(lzo->type));
|
||||
@ -1888,7 +1889,8 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
lzt == local_zone_inform_deny ||
|
||||
lzt == local_zone_inform_redirect)
|
||||
&& repinfo)
|
||||
lz_inform_print(z, qinfo, repinfo);
|
||||
lz_inform_print(z, qinfo, &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
|
||||
if(lzt != local_zone_always_refuse
|
||||
&& lzt != local_zone_always_transparent
|
||||
|
@ -806,7 +806,7 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
|
||||
/* Fake the ECS data from the client's IP */
|
||||
struct ecs_data ecs;
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
subnet_option_from_ss(&rep->addr, &ecs, mesh->env->cfg);
|
||||
subnet_option_from_ss(&rep->client_addr, &ecs, mesh->env->cfg);
|
||||
if(ecs.subnet_validdata == 0) {
|
||||
log_err("prefetch_subnet subnet_option_from_ss: invalid data");
|
||||
return;
|
||||
@ -1488,8 +1488,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
}
|
||||
/* Log reply sent */
|
||||
if(m->s.env->cfg->log_replies) {
|
||||
log_reply_info(NO_VERBOSE, &m->s.qinfo, &r->query_reply.addr,
|
||||
r->query_reply.addrlen, duration, 0, r_buffer);
|
||||
log_reply_info(NO_VERBOSE, &m->s.qinfo,
|
||||
&r->query_reply.client_addr,
|
||||
r->query_reply.client_addrlen, duration, 0, r_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1530,7 +1531,8 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
respip_inform_print(mstate->s.respip_action_info,
|
||||
r->qname, mstate->s.qinfo.qtype,
|
||||
mstate->s.qinfo.qclass, r->local_alias,
|
||||
&r->query_reply);
|
||||
&r->query_reply.client_addr,
|
||||
r->query_reply.client_addrlen);
|
||||
if(mstate->s.env->cfg->stat_extended &&
|
||||
mstate->s.respip_action_info->rpz_used) {
|
||||
if(mstate->s.respip_action_info->rpz_disabled)
|
||||
@ -2180,7 +2182,8 @@ mesh_serve_expired_callback(void* arg)
|
||||
if(actinfo.addrinfo) {
|
||||
respip_inform_print(&actinfo, r->qname,
|
||||
qstate->qinfo.qtype, qstate->qinfo.qclass,
|
||||
r->local_alias, &r->query_reply);
|
||||
r->local_alias, &r->query_reply.client_addr,
|
||||
r->query_reply.client_addrlen);
|
||||
|
||||
if(qstate->env->cfg->stat_extended && actinfo.rpz_used) {
|
||||
if(actinfo.rpz_disabled)
|
||||
|
@ -721,12 +721,12 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
pend->next_free = NULL;
|
||||
pend->query = w;
|
||||
pend->reuse.outnet = w->outnet;
|
||||
pend->c->repinfo.addrlen = w->addrlen;
|
||||
pend->c->repinfo.remote_addrlen = w->addrlen;
|
||||
pend->c->tcp_more_read_again = &pend->reuse.cp_more_read_again;
|
||||
pend->c->tcp_more_write_again = &pend->reuse.cp_more_write_again;
|
||||
pend->reuse.cp_more_read_again = 0;
|
||||
pend->reuse.cp_more_write_again = 0;
|
||||
memcpy(&pend->c->repinfo.addr, &w->addr, w->addrlen);
|
||||
memcpy(&pend->c->repinfo.remote_addr, &w->addr, w->addrlen);
|
||||
pend->reuse.pending = pend;
|
||||
|
||||
/* Remove from tree in case the is_ssl will be different and causes the
|
||||
@ -1417,11 +1417,11 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
|
||||
/* setup lookup key */
|
||||
key.id = (unsigned)LDNS_ID_WIRE(sldns_buffer_begin(c->buffer));
|
||||
memcpy(&key.addr, &reply_info->addr, reply_info->addrlen);
|
||||
key.addrlen = reply_info->addrlen;
|
||||
memcpy(&key.addr, &reply_info->remote_addr, reply_info->remote_addrlen);
|
||||
key.addrlen = reply_info->remote_addrlen;
|
||||
verbose(VERB_ALGO, "Incoming reply id = %4.4x", key.id);
|
||||
log_addr(VERB_ALGO, "Incoming reply addr =",
|
||||
&reply_info->addr, reply_info->addrlen);
|
||||
&reply_info->remote_addr, reply_info->remote_addrlen);
|
||||
|
||||
/* find it, see if this thing is a valid query response */
|
||||
verbose(VERB_ALGO, "lookup size is %d entries", (int)outnet->pending->count);
|
||||
@ -1690,7 +1690,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, NULL);
|
||||
outnet->udp_buff, 0, outnet_udp_cb, outnet, NULL);
|
||||
if(!pc->cp) {
|
||||
log_err("malloc failed");
|
||||
free(pc);
|
||||
@ -3103,8 +3103,8 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||
rep = &r2;
|
||||
r2.c = c;
|
||||
}
|
||||
memcpy(&rep->addr, &sq->addr, sq->addrlen);
|
||||
rep->addrlen = sq->addrlen;
|
||||
memcpy(&rep->remote_addr, &sq->addr, sq->addrlen);
|
||||
rep->remote_addrlen = sq->addrlen;
|
||||
serviced_callbacks(sq, error, c, rep);
|
||||
return 0;
|
||||
}
|
||||
@ -3582,7 +3582,7 @@ outnet_comm_point_for_udp(struct outside_network* outnet,
|
||||
if(fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
cp = comm_point_create_udp(outnet->base, fd, outnet->udp_buff,
|
||||
cp = comm_point_create_udp(outnet->base, fd, outnet->udp_buff, 0,
|
||||
cb, cb_arg, NULL);
|
||||
if(!cp) {
|
||||
log_err("malloc failure");
|
||||
@ -3670,8 +3670,8 @@ outnet_comm_point_for_tcp(struct outside_network* outnet,
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
cp->repinfo.addrlen = to_addrlen;
|
||||
memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
|
||||
cp->repinfo.remote_addrlen = to_addrlen;
|
||||
memcpy(&cp->repinfo.remote_addr, to_addr, to_addrlen);
|
||||
|
||||
/* setup for SSL (if needed) */
|
||||
if(ssl) {
|
||||
@ -3746,8 +3746,8 @@ outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
cp->repinfo.addrlen = to_addrlen;
|
||||
memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
|
||||
cp->repinfo.remote_addrlen = to_addrlen;
|
||||
memcpy(&cp->repinfo.remote_addr, to_addr, to_addrlen);
|
||||
|
||||
/* setup for SSL (if needed) */
|
||||
if(ssl) {
|
||||
|
@ -1392,11 +1392,13 @@ log_rpz_apply(char* trigger, uint8_t* dname, struct addr_tree_node* addrnode,
|
||||
dnamestr[0]=0;
|
||||
}
|
||||
if(repinfo) {
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
|
||||
port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
|
||||
addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip));
|
||||
port = ntohs(((struct sockaddr_in*)&repinfo->client_addr)->sin_port);
|
||||
} else if(ms && ms->mesh_info && ms->mesh_info->reply_list) {
|
||||
addr_to_str(&ms->mesh_info->reply_list->query_reply.addr, ms->mesh_info->reply_list->query_reply.addrlen, ip, sizeof(ip));
|
||||
port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.addr)->sin_port);
|
||||
addr_to_str(&ms->mesh_info->reply_list->query_reply.client_addr,
|
||||
ms->mesh_info->reply_list->query_reply.client_addrlen,
|
||||
ip, sizeof(ip));
|
||||
port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.client_addr)->sin_port);
|
||||
} else {
|
||||
ip[0]=0;
|
||||
port = 0;
|
||||
@ -1468,7 +1470,9 @@ rpz_resolve_client_action_and_zone(struct auth_zones* az, struct query_info* qin
|
||||
}
|
||||
z = rpz_find_zone(r->local_zones, qinfo->qname, qinfo->qname_len,
|
||||
qinfo->qclass, 0, 0, 0);
|
||||
node = rpz_ipbased_trigger_lookup(r->client_set, &repinfo->addr, repinfo->addrlen, "clientip");
|
||||
node = rpz_ipbased_trigger_lookup(r->client_set,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
"clientip");
|
||||
if((z || node) && r->action_override == RPZ_DISABLED_ACTION) {
|
||||
if(r->log)
|
||||
log_rpz_apply((node?"clientip":"qname"),
|
||||
|
@ -338,6 +338,8 @@ interfacechecks(struct config_file* cfg)
|
||||
int i, j, i2, j2;
|
||||
char*** resif = NULL;
|
||||
int* num_resif = NULL;
|
||||
char portbuf[32];
|
||||
snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
|
||||
|
||||
if(cfg->num_ifs != 0) {
|
||||
resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
|
||||
@ -359,9 +361,21 @@ interfacechecks(struct config_file* cfg)
|
||||
fatal_exit("could not resolve interface names, for %s",
|
||||
cfg->ifs[i]);
|
||||
}
|
||||
/* check for port combinations that are not supported */
|
||||
if(if_is_pp2(resif[i][0], portbuf, cfg->proxy_protocol_port)) {
|
||||
if(if_is_dnscrypt(resif[i][0], portbuf,
|
||||
cfg->dnscrypt_port)) {
|
||||
fatal_exit("PROXYv2 and DNSCrypt combination not "
|
||||
"supported!");
|
||||
} else if(if_is_https(resif[i][0], portbuf,
|
||||
cfg->https_port)) {
|
||||
fatal_exit("PROXYv2 and DoH combination not "
|
||||
"supported!");
|
||||
}
|
||||
}
|
||||
/* search for duplicates in the returned addresses */
|
||||
for(j=0; j<num_resif[i]; j++) {
|
||||
if(!extstrtoaddr(resif[i][j], &a, &alen, UNBOUND_DNS_PORT)) {
|
||||
if(!extstrtoaddr(resif[i][j], &a, &alen, cfg->port)) {
|
||||
if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
|
||||
fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
|
||||
resif[i][j], cfg->ifs[i]);
|
||||
|
@ -16,7 +16,7 @@ NEED_WHOAMI='07-confroot.tdir'
|
||||
NEED_IPV6='fwd_ancil.tdir fwd_tcp_tc6.tdir stub_udp6.tdir edns_cache.tdir'
|
||||
NEED_NOMINGW='tcp_sigpipe.tdir 07-confroot.tdir 08-host-lib.tdir fwd_ancil.tdir'
|
||||
NEED_DNSCRYPT_PROXY='dnscrypt_queries.tdir dnscrypt_queries_chacha.tdir'
|
||||
NEED_UNSHARE='acl_interface.tdir'
|
||||
NEED_UNSHARE='acl_interface.tdir proxy_protocol.tdir'
|
||||
|
||||
# test if dig and ldns-testns are available.
|
||||
test_tool_avail "dig"
|
||||
|
@ -384,8 +384,8 @@ answer_callback_from_entry(struct replay_runtime* runtime,
|
||||
fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len,
|
||||
pend->tcp_pkt_counter);
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = pend->addrlen;
|
||||
memcpy(&repinfo.addr, &pend->addr, pend->addrlen);
|
||||
repinfo.remote_addrlen = pend->addrlen;
|
||||
memcpy(&repinfo.remote_addr, &pend->addr, pend->addrlen);
|
||||
if(!pend->serviced) {
|
||||
if(entry && entry->reply_list->next &&
|
||||
pend->tcp_pkt_counter < count_reply_packets(entry)) {
|
||||
@ -415,7 +415,7 @@ answer_check_it(struct replay_runtime* runtime)
|
||||
tr = transport_udp;
|
||||
if((runtime->now->addrlen == 0 || sockaddr_cmp(
|
||||
&runtime->now->addr, runtime->now->addrlen,
|
||||
&ans->repinfo.addr, ans->repinfo.addrlen) == 0) &&
|
||||
&ans->repinfo.remote_addr, ans->repinfo.remote_addrlen) == 0) &&
|
||||
find_match(runtime->now->match, ans->pkt,
|
||||
ans->pkt_len, tr)) {
|
||||
log_info("testbound matched event entry from line %d",
|
||||
@ -453,10 +453,12 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
|
||||
repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point));
|
||||
if(!repinfo.c)
|
||||
fatal_exit("out of memory in fake_front_query");
|
||||
repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
repinfo.remote_addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
if(todo->addrlen != 0) {
|
||||
repinfo.addrlen = todo->addrlen;
|
||||
memcpy(&repinfo.addr, &todo->addr, todo->addrlen);
|
||||
repinfo.remote_addrlen = todo->addrlen;
|
||||
memcpy(&repinfo.remote_addr, &todo->addr, todo->addrlen);
|
||||
repinfo.client_addrlen = todo->addrlen;
|
||||
memcpy(&repinfo.client_addr, &todo->addr, todo->addrlen);
|
||||
}
|
||||
repinfo.c->fd = -1;
|
||||
repinfo.c->ev = (struct internal_event*)runtime;
|
||||
@ -510,8 +512,8 @@ fake_pending_callback(struct replay_runtime* runtime,
|
||||
p->pkt_len, p->tcp_pkt_counter);
|
||||
}
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = p->addrlen;
|
||||
memcpy(&repinfo.addr, &p->addr, p->addrlen);
|
||||
repinfo.remote_addrlen = p->addrlen;
|
||||
memcpy(&repinfo.remote_addr, &p->addr, p->addrlen);
|
||||
if(!p->serviced) {
|
||||
if(todo->match && todo->match->reply_list->next && !error &&
|
||||
p->tcp_pkt_counter < count_reply_packets(todo->match)) {
|
||||
@ -1663,6 +1665,7 @@ 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),
|
||||
int ATTR_UNUSED(pp2_enabled),
|
||||
comm_point_callback_type* ATTR_UNUSED(callback),
|
||||
void* ATTR_UNUSED(callback_arg),
|
||||
struct unbound_socket* ATTR_UNUSED(socket))
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "util/locks.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/proxy_protocol.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
@ -71,6 +72,7 @@ static void usage(char* argv[])
|
||||
printf("usage: %s [options] name type class ...\n", argv[0]);
|
||||
printf(" sends the name-type-class queries over TCP.\n");
|
||||
printf("-f server what ipaddr@portnr to send the queries to\n");
|
||||
printf("-p client what ipaddr@portnr to include in PROXYv2\n");
|
||||
printf("-u use UDP. No retries are attempted.\n");
|
||||
printf("-n do not wait for an answer.\n");
|
||||
printf("-a print answers as they arrive.\n");
|
||||
@ -82,18 +84,17 @@ static void usage(char* argv[])
|
||||
|
||||
/** open TCP socket to svr */
|
||||
static int
|
||||
open_svr(const char* svr, int udp)
|
||||
open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int fd = -1;
|
||||
/* svr can be ip@port */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if(!extstrtoaddr(svr, &addr, &addrlen, UNBOUND_DNS_PORT)) {
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) {
|
||||
printf("fatal: bad server specs '%s'\n", svr);
|
||||
exit(1);
|
||||
}
|
||||
fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
|
||||
fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET,
|
||||
udp?SOCK_DGRAM:SOCK_STREAM, 0);
|
||||
if(fd == -1) {
|
||||
#ifndef USE_WINSOCK
|
||||
@ -103,7 +104,7 @@ open_svr(const char* svr, int udp)
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
|
||||
if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("connect() error");
|
||||
#else
|
||||
@ -117,10 +118,11 @@ open_svr(const char* svr, int udp)
|
||||
/** write a query over the TCP fd */
|
||||
static void
|
||||
write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
sldns_buffer* proxy_buf, int pp2_parsed,
|
||||
const char* strname, const char* strtype, const char* strclass)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
uint16_t len;
|
||||
size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
|
||||
/* qname */
|
||||
qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
|
||||
if(!qinfo.qname) {
|
||||
@ -152,9 +154,27 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
attach_edns_record(buf, &edns);
|
||||
}
|
||||
|
||||
/* we need to send the PROXYv2 information in every UDP message */
|
||||
if(udp && pp2_parsed) {
|
||||
/* append the proxy_buf with the buf's content
|
||||
* and use that for sending */
|
||||
if(sldns_buffer_capacity(proxy_buf) <
|
||||
sldns_buffer_limit(proxy_buf) +
|
||||
sldns_buffer_limit(buf)) {
|
||||
printf("buffer too small for packet + proxy");
|
||||
exit(1);
|
||||
}
|
||||
sldns_buffer_clear(proxy_buf);
|
||||
sldns_buffer_skip(proxy_buf, proxy_buf_limit);
|
||||
sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf),
|
||||
sldns_buffer_limit(buf));
|
||||
sldns_buffer_flip(proxy_buf);
|
||||
buf = proxy_buf;
|
||||
}
|
||||
|
||||
/* send it */
|
||||
if(!udp) {
|
||||
len = (uint16_t)sldns_buffer_limit(buf);
|
||||
uint16_t len = (uint16_t)sldns_buffer_limit(buf);
|
||||
len = htons(len);
|
||||
if(ssl) {
|
||||
if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
|
||||
@ -187,12 +207,15 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() data failed");
|
||||
#else
|
||||
printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
|
||||
printf("send data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* reset the proxy_buf for next packet */
|
||||
sldns_buffer_set_limit(proxy_buf, proxy_buf_limit);
|
||||
free(qinfo.qname);
|
||||
}
|
||||
|
||||
@ -324,17 +347,40 @@ static int get_random(void)
|
||||
return (int)arc4random();
|
||||
}
|
||||
|
||||
/* parse the pp2_client and populate the proxy_buffer
|
||||
* It doesn't populate the destination parts. */
|
||||
static int parse_pp2_client(const char* pp2_client, int udp,
|
||||
sldns_buffer* proxy_buf)
|
||||
{
|
||||
struct sockaddr_storage pp2_addr;
|
||||
socklen_t pp2_addrlen = 0;
|
||||
memset(&pp2_addr, 0, sizeof(pp2_addr));
|
||||
if(*pp2_client == 0) return 0;
|
||||
if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) {
|
||||
printf("fatal: bad proxy client specs '%s'\n", pp2_client);
|
||||
exit(1);
|
||||
}
|
||||
sldns_buffer_clear(proxy_buf);
|
||||
pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
|
||||
sldns_buffer_flip(proxy_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** send the TCP queries and print answers */
|
||||
static void
|
||||
send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
int delay, int num, char** qs)
|
||||
send_em(const char* svr, const char* pp2_client, int udp, int usessl,
|
||||
int noanswer, int onarrival, int delay, int num, char** qs)
|
||||
{
|
||||
sldns_buffer* buf = sldns_buffer_new(65553);
|
||||
int fd = open_svr(svr, udp);
|
||||
int i, wait_results = 0;
|
||||
sldns_buffer* proxy_buf = sldns_buffer_new(65553);
|
||||
struct sockaddr_storage svr_addr;
|
||||
socklen_t svr_addrlen;
|
||||
int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
|
||||
int i, wait_results = 0, pp2_parsed;
|
||||
SSL_CTX* ctx = NULL;
|
||||
SSL* ssl = NULL;
|
||||
if(!buf) fatal_exit("out of memory");
|
||||
pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
|
||||
if(usessl) {
|
||||
ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
|
||||
if(!ctx) fatal_exit("cannot create ssl ctx");
|
||||
@ -361,6 +407,28 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send the PROXYv2 information once per stream */
|
||||
if(!udp && pp2_parsed) {
|
||||
if(ssl) {
|
||||
if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf),
|
||||
(int)sldns_buffer_limit(proxy_buf)) <= 0) {
|
||||
log_crypto_err("cannot SSL_write");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if(send(fd, (void*)sldns_buffer_begin(proxy_buf),
|
||||
sldns_buffer_limit(proxy_buf), 0) <
|
||||
(ssize_t)sldns_buffer_limit(proxy_buf)) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() data failed");
|
||||
#else
|
||||
printf("send data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0; i<num; i+=3) {
|
||||
if (delay != 0) {
|
||||
#ifdef HAVE_SLEEP
|
||||
@ -370,8 +438,9 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
#endif
|
||||
}
|
||||
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
|
||||
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
|
||||
qs[i+1], qs[i+2]);
|
||||
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf,
|
||||
pp2_parsed,
|
||||
qs[i], qs[i+1], qs[i+2]);
|
||||
/* print at least one result */
|
||||
if(onarrival) {
|
||||
wait_results += 1; /* one more answer to fetch */
|
||||
@ -390,6 +459,7 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
}
|
||||
sock_close(fd);
|
||||
sldns_buffer_free(buf);
|
||||
sldns_buffer_free(proxy_buf);
|
||||
printf("orderly exit\n");
|
||||
}
|
||||
|
||||
@ -422,6 +492,7 @@ int main(int argc, char** argv)
|
||||
{
|
||||
int c;
|
||||
const char* svr = "127.0.0.1";
|
||||
const char* pp2_client = "";
|
||||
int udp = 0;
|
||||
int noanswer = 0;
|
||||
int onarrival = 0;
|
||||
@ -451,11 +522,14 @@ int main(int argc, char** argv)
|
||||
if(argc == 1) {
|
||||
usage(argv);
|
||||
}
|
||||
while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
|
||||
while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) {
|
||||
switch(c) {
|
||||
case 'f':
|
||||
svr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
pp2_client = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
onarrival = 1;
|
||||
break;
|
||||
@ -508,7 +582,7 @@ int main(int argc, char** argv)
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
#endif
|
||||
}
|
||||
send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);
|
||||
send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
|
||||
checklock_stop();
|
||||
#ifdef USE_WINSOCK
|
||||
WSACleanup();
|
||||
|
10
testdata/04-checkconf.tdir/04-checkconf.test
vendored
10
testdata/04-checkconf.tdir/04-checkconf.test
vendored
@ -28,6 +28,12 @@ if grep "define UB_ON_WINDOWS 1" ../../config.h; then
|
||||
else
|
||||
onwin=0
|
||||
fi
|
||||
# detect dnscrypt
|
||||
if grep "define USE_DNSCRYPT 1" ../../config.h; then
|
||||
with_dnscrypt=1
|
||||
else
|
||||
with_dnscrypt=0
|
||||
fi
|
||||
|
||||
# test check of config files.
|
||||
for f in bad.*; do
|
||||
@ -37,6 +43,10 @@ for f in bad.*; do
|
||||
echo "skipped on windows"
|
||||
continue
|
||||
fi
|
||||
if test $f = "bad.proxy-and-dnscrypt" -a $with_dnscrypt -eq 0; then
|
||||
echo "skipped; no DNSCRYPT support"
|
||||
continue
|
||||
fi
|
||||
|
||||
$PRE/unbound-checkconf $f
|
||||
if test $? != 1; then
|
||||
|
5
testdata/04-checkconf.tdir/bad.proxy-and-dnscrypt
vendored
Normal file
5
testdata/04-checkconf.tdir/bad.proxy-and-dnscrypt
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
server:
|
||||
interface: 127.0.0.1
|
||||
proxy-protocol-port: 53
|
||||
dnscrypt:
|
||||
dnscrypt-port: 53
|
4
testdata/04-checkconf.tdir/bad.proxy-and-https
vendored
Normal file
4
testdata/04-checkconf.tdir/bad.proxy-and-https
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
server:
|
||||
interface: 127.0.0.1
|
||||
proxy-protocol-port: 53
|
||||
https-port: 53
|
34
testdata/proxy_protocol.tdir/proxy_protocol.conf
vendored
Normal file
34
testdata/proxy_protocol.tdir/proxy_protocol.conf
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
server:
|
||||
verbosity: 5
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1@@PORT@
|
||||
interface: 127.0.0.1@@PROXYPORT@
|
||||
interface: 127.0.0.1@@PROXYTLSPORT@
|
||||
interface: @INTERFACE_ALLOW_ADDR@@@PORT@
|
||||
interface: @INTERFACE_ALLOW_ADDR@@@PROXYPORT@
|
||||
interface: @INTERFACE_ALLOW_ADDR@@@PROXYTLSPORT@
|
||||
interface: @INTERFACE_REFUSE_ADDR@@@PORT@
|
||||
interface: @INTERFACE_REFUSE_ADDR@@@PROXYPORT@
|
||||
interface: @INTERFACE_REFUSE_ADDR@@@PROXYTLSPORT@
|
||||
proxy-protocol-port: @PROXYPORT@
|
||||
proxy-protocol-port: @PROXYTLSPORT@
|
||||
tls-port: @PROXYTLSPORT@
|
||||
use-syslog: no
|
||||
directory: .
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
tls-service-key: "unbound_server.key"
|
||||
tls-service-pem: "unbound_server.pem"
|
||||
|
||||
# 127.0.0.0/8 is allowed by default.
|
||||
access-control: @CLIENT_ADDR_ALLOW@/32 allow
|
||||
access-control: @CLIENT_ADDR_REFUSE@/32 refuse
|
||||
access-control: @CLIENT_ADDR_ALLOW6@/128 allow
|
||||
access-control: @CLIENT_ADDR_REFUSE6@/128 refuse
|
||||
access-control: @INTERFACE_ALLOW_ADDR@/32 allow
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@@TOPORT@"
|
16
testdata/proxy_protocol.tdir/proxy_protocol.dsc
vendored
Normal file
16
testdata/proxy_protocol.tdir/proxy_protocol.dsc
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
BaseName: proxy_protocol
|
||||
Version: 1.0
|
||||
Description: Test proxy protocol
|
||||
CreationDate: Mon Mar 14 16:17:00 CET 2022
|
||||
Maintainer: Yorgos Thessalonikefs
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: proxy_protocol.pre
|
||||
Post: proxy_protocol.post
|
||||
Test: proxy_protocol.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
12
testdata/proxy_protocol.tdir/proxy_protocol.post
vendored
Normal file
12
testdata/proxy_protocol.tdir/proxy_protocol.post
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# #-- proxy_protocol.post --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# source the test var file when it's there
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
#
|
||||
# do your teardown here
|
||||
. ../common.sh
|
||||
kill_pid $FWD_PID
|
||||
kill_pid $UNBOUND_PID
|
||||
cat unbound.log
|
||||
exit 0
|
66
testdata/proxy_protocol.tdir/proxy_protocol.pre
vendored
Normal file
66
testdata/proxy_protocol.tdir/proxy_protocol.pre
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
# #-- proxy_protocol.pre--#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
# This test uses the unshare utility
|
||||
if test ! -x "`which unshare 2>&1`"; then
|
||||
skip_test "no unshare (from util-linux package) available, skip test"
|
||||
fi
|
||||
|
||||
get_make
|
||||
(cd $PRE; $MAKE streamtcp)
|
||||
|
||||
get_random_port 4
|
||||
UNBOUND_PORT=$RND_PORT
|
||||
FWD_PORT=$(($RND_PORT + 1))
|
||||
PROXY_PORT=$(($RND_PORT + 2))
|
||||
PROXY_TLS_PORT=$(($RND_PORT + 3))
|
||||
|
||||
INTERFACE_ALLOW=eth123
|
||||
INTERFACE_ALLOW_ADDR=10.1.2.3
|
||||
INTERFACE_REFUSE=eth234
|
||||
INTERFACE_REFUSE_ADDR=10.2.3.4
|
||||
|
||||
CLIENT_ADDR_ALLOW=1.2.3.4
|
||||
CLIENT_ADDR_ALLOW6=2001:db8::cafe:cafe
|
||||
CLIENT_ADDR_REFUSE=5.6.7.8
|
||||
CLIENT_ADDR_REFUSE6=2001:db8::dead:beef
|
||||
|
||||
# make config file
|
||||
sed \
|
||||
-e 's/@PORT\@/'$UNBOUND_PORT'/' \
|
||||
-e 's/@TOPORT\@/'$FWD_PORT'/' \
|
||||
-e 's/@PROXYPORT\@/'$PROXY_PORT'/' \
|
||||
-e 's/@PROXYTLSPORT\@/'$PROXY_TLS_PORT'/' \
|
||||
-e 's/@INTERFACE_ALLOW_ADDR\@/'$INTERFACE_ALLOW_ADDR'/' \
|
||||
-e 's/@INTERFACE_REFUSE_ADDR\@/'$INTERFACE_REFUSE_ADDR'/' \
|
||||
-e 's/@CLIENT_ADDR_ALLOW\@/'$CLIENT_ADDR_ALLOW'/' \
|
||||
-e 's/@CLIENT_ADDR_ALLOW6\@/'$CLIENT_ADDR_ALLOW6'/' \
|
||||
-e 's/@CLIENT_ADDR_REFUSE\@/'$CLIENT_ADDR_REFUSE'/' \
|
||||
-e 's/@CLIENT_ADDR_REFUSE6\@/'$CLIENT_ADDR_REFUSE6'/' \
|
||||
< proxy_protocol.conf > ub.conf
|
||||
|
||||
if test -x "`which bash`"; then
|
||||
shell="bash"
|
||||
else
|
||||
shell="sh"
|
||||
fi
|
||||
|
||||
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
|
||||
echo "PROXY_PORT=$PROXY_PORT" >> .tpkg.var.test
|
||||
echo "PROXY_TLS_PORT=$PROXY_TLS_PORT" >> .tpkg.var.test
|
||||
echo "INTERFACE_ALLOW=$INTERFACE_ALLOW" >> .tpkg.var.test
|
||||
echo "INTERFACE_ALLOW_ADDR=$INTERFACE_ALLOW_ADDR" >> .tpkg.var.test
|
||||
echo "INTERFACE_REFUSE=$INTERFACE_REFUSE" >> .tpkg.var.test
|
||||
echo "INTERFACE_REFUSE_ADDR=$INTERFACE_REFUSE_ADDR" >> .tpkg.var.test
|
||||
echo "CLIENT_ADDR_ALLOW=$CLIENT_ADDR_ALLOW" >> .tpkg.var.test
|
||||
echo "CLIENT_ADDR_ALLOW6=$CLIENT_ADDR_ALLOW6" >> .tpkg.var.test
|
||||
echo "CLIENT_ADDR_REFUSE=$CLIENT_ADDR_REFUSE" >> .tpkg.var.test
|
||||
echo "CLIENT_ADDR_REFUSE6=$CLIENT_ADDR_REFUSE6" >> .tpkg.var.test
|
||||
echo "shell=$shell" >> .tpkg.var.test
|
12
testdata/proxy_protocol.tdir/proxy_protocol.test
vendored
Normal file
12
testdata/proxy_protocol.tdir/proxy_protocol.test
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# #-- proxy_protocol.test --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
# Run the scenario in an unshared namespace
|
||||
unshare -rUn $shell proxy_protocol.test.scenario
|
||||
exit $?
|
193
testdata/proxy_protocol.tdir/proxy_protocol.test.scenario
vendored
Normal file
193
testdata/proxy_protocol.tdir/proxy_protocol.test.scenario
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
# #-- proxy_protocol.test.scenario --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
ip addr add 127.0.0.1 dev lo
|
||||
ip link set lo up
|
||||
|
||||
ip link add $INTERFACE_ALLOW type dummy
|
||||
ip addr add $INTERFACE_ALLOW_ADDR dev $INTERFACE_ALLOW
|
||||
ip link set $INTERFACE_ALLOW up
|
||||
|
||||
ip link add $INTERFACE_REFUSE type dummy
|
||||
ip addr add $INTERFACE_REFUSE_ADDR dev $INTERFACE_REFUSE
|
||||
ip link set $INTERFACE_REFUSE up
|
||||
|
||||
# start forwarder in the background
|
||||
get_ldns_testns
|
||||
$LDNS_TESTNS -p $FWD_PORT proxy_protocol.testns >fwd.log 2>&1 &
|
||||
FWD_PID=$!
|
||||
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
|
||||
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
|
||||
wait_ldns_testns_up fwd.log
|
||||
wait_unbound_up unbound.log
|
||||
|
||||
# call streamtcp and check return value
|
||||
do_streamtcp () {
|
||||
$PRE/streamtcp $* A IN >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
echo "exit status not OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
send_query () {
|
||||
server=$1
|
||||
client=$2
|
||||
prot=$3
|
||||
query=$4
|
||||
echo -n "> query $query to $server"
|
||||
port=$UNBOUND_PORT
|
||||
if test ! -z "$client"; then
|
||||
port=$PROXY_PORT
|
||||
fi
|
||||
case $prot in
|
||||
-u)
|
||||
echo -n " (over UDP)"
|
||||
;;
|
||||
-s)
|
||||
echo -n " (over TLS)"
|
||||
port=$PROXY_TLS_PORT
|
||||
;;
|
||||
*)
|
||||
echo -n " (over TCP)"
|
||||
esac
|
||||
if test ! -z "$client"; then
|
||||
echo -n " ($client proxied)"
|
||||
fi
|
||||
echo
|
||||
do_streamtcp $prot -f $server@$port $client $query
|
||||
#cat outfile
|
||||
}
|
||||
|
||||
expect_answer () {
|
||||
#query=$1
|
||||
#answer=$2
|
||||
if grep "$query" outfile | grep "$answer"; then
|
||||
echo "content OK"
|
||||
echo
|
||||
else
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "result contents not OK"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
expect_refuse () {
|
||||
if grep "rcode: REFUSE" outfile; then
|
||||
echo "content OK"
|
||||
echo
|
||||
else
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "result contents not OK"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Start the test
|
||||
|
||||
# Query without PROXYv2
|
||||
# Client localhost
|
||||
# Expect the result back
|
||||
server=127.0.0.1
|
||||
client=""
|
||||
query="two.example.net."
|
||||
answer="2.2.2.2"
|
||||
for prot in "-u" ""; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_answer
|
||||
done
|
||||
|
||||
# Query with PROXYv2
|
||||
# Client $CLIENT_ADDR_ALLOW should be allowed
|
||||
# Expect the result back
|
||||
server=127.0.0.1
|
||||
client="-p $CLIENT_ADDR_ALLOW@1234"
|
||||
query="one.example.net."
|
||||
answer="1.1.1.1"
|
||||
for prot in "-u" "" "-s"; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_answer
|
||||
done
|
||||
|
||||
# Query with PROXYv2
|
||||
# Client $CLIENT_ADDR_ALLOW6 should be allowed
|
||||
# Expect the result back
|
||||
server=127.0.0.1
|
||||
client="-p $CLIENT_ADDR_ALLOW6@1234"
|
||||
query="one.example.net."
|
||||
answer="1.1.1.1"
|
||||
for prot in "-u" "" "-s"; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_answer
|
||||
done
|
||||
|
||||
# Query with PROXYv2
|
||||
# Client $CLIENT_ADDR_REFUSE should be refused
|
||||
# Expect the REFUSE back
|
||||
server=127.0.0.1
|
||||
client="-p $CLIENT_ADDR_REFUSE"
|
||||
query="one.example.net."
|
||||
answer=""
|
||||
for prot in "-u" "" "-s"; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_refuse
|
||||
done
|
||||
|
||||
# Query with PROXYv2
|
||||
# Client $CLIENT_ADDR_REFUSE6 should be refused
|
||||
# Expect the REFUSE back
|
||||
server=127.0.0.1
|
||||
client="-p $CLIENT_ADDR_REFUSE6"
|
||||
query="one.example.net."
|
||||
answer=""
|
||||
for prot in "-u" "" "-s"; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_refuse
|
||||
done
|
||||
|
||||
# Query with PROXYv2
|
||||
# Client $CLIENT_ADDR_ALLOW should be allowed; proxy source address should be allowed
|
||||
# Expect the result back
|
||||
server=$INTERFACE_ALLOW_ADDR
|
||||
client="-p $CLIENT_ADDR_ALLOW@1234"
|
||||
query="one.example.net."
|
||||
answer="1.1.1.1"
|
||||
for prot in "-u" "" "-s"; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_answer
|
||||
done
|
||||
|
||||
# Query with PROXYv2
|
||||
# Client $CLIENT_ADDR_ALLOW should be allowed; proxy source address should be refused
|
||||
# Expect the REFUSE back
|
||||
server=$INTERFACE_REFUSE_ADDR
|
||||
client="-p $CLIENT_ADDR_ALLOW@1234"
|
||||
query="one.example.net."
|
||||
answer=""
|
||||
for prot in "-u" "" "-s"; do
|
||||
send_query "$server" "$client" "$prot" "$query"
|
||||
expect_refuse
|
||||
done
|
||||
|
||||
echo "OK"
|
||||
exit 0
|
||||
|
23
testdata/proxy_protocol.tdir/proxy_protocol.testns
vendored
Normal file
23
testdata/proxy_protocol.tdir/proxy_protocol.testns
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
; nameserver test file
|
||||
$ORIGIN example.net.
|
||||
$TTL 3600
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
REPLY QR RD RA NOERROR
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
one IN A
|
||||
SECTION ANSWER
|
||||
one IN A 1.1.1.1
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
REPLY QR RD RA NOERROR
|
||||
ADJUST copy_id
|
||||
SECTION QUESTION
|
||||
two IN A
|
||||
SECTION ANSWER
|
||||
two IN A 2.2.2.2
|
||||
ENTRY_END
|
39
testdata/proxy_protocol.tdir/unbound_server.key
vendored
Normal file
39
testdata/proxy_protocol.tdir/unbound_server.key
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIG5AIBAAKCAYEAvjSVSN2QMXudpzukdLCqgg/IOhCX8KYkD0FFFfWcQjgKq5wI
|
||||
0x41iG32a6wbGanre4IX7VxaSPu9kkHfnGgynCk5nwDRedE/FLFhAU78PoT0+Nqq
|
||||
GRS7XVQ24vLmIz9Hqc2Ozx1um1BXBTmIT0UfN2e22I0LWQ6a3seZlEDRj45gnk7Z
|
||||
uh9MDgotaBdm+v1JAbupSf6Zis4VEH3JNdvVGE3O1DHEIeuuz/3BDhpf6WBDH+8K
|
||||
WaBe1ca4TZHr9ThL2gEMEfAQl0wXDwRWRoi3NjNMH+mw0L1rjwThI5GXqNIee7o5
|
||||
FzUReSXZuTdFMyGe3Owcx+XoYnwi6cplSNoGsDBu4B9bKKglR9YleJVw4L4Xi8xP
|
||||
q6O9UPj4+nypHk/DOoC7DIM3ufN0yxPBsFo5TVowxfhdjZXJbbftd2TZv7AH8+XL
|
||||
A5UoZgRzXgzECelXSCTBFlMTnT48LfA9pMLydyjAz2UdPHs5Iv+TK5nnI+aJoeaP
|
||||
7kFZSngxdy1+A/bNAgMBAAECggGBALpTOIqQwVg4CFBylL/a8K1IWJTI/I65sklf
|
||||
XxYL7G7SB2HlEJ//z+E+F0+S4Vlao1vyLQ5QkgE82pAUB8FoMWvY1qF0Y8A5wtm6
|
||||
iZSGk4OLK488ZbT8Ii9i+AGKgPe2XbVxsJwj8N4k7Zooqec9hz73Up8ATEWJkRz7
|
||||
2u7oMGG4z91E0PULA64dOi3l/vOQe5w/Aa+CwVbAWtI05o7kMvQEBMDJn6C7CByo
|
||||
MB5op9wueJMnz7PM7hns+U7Dy6oE4ljuolJUy51bDzFWwoM54cRoQqLFNHd8JVQj
|
||||
WxldCkbfF43iyprlsEcUrTyUjtdA+ZeiG39vg/mtdmgNpGmdupHJZQvSuG8IcVlz
|
||||
O+eMSeQS1QXPD6Ik8UK4SU0h+zOl8xIWtRrsxQuh4fnTN40udm/YUWl/6gOebsBI
|
||||
IrVLlKGqJSfB3tMjpCRqdTzJ0dA9keVpkqm2ugZkxEf1+/efq/rFIQ2pUBLCqNTN
|
||||
qpNqruK8y8FphP30I2uI4Ej2UIB8AQKBwQDd2Yptj2FyDyaXCycsyde0wYkNyzGU
|
||||
dRnzdibfHnMZwjgTjwAwgIUBVIS8H0/z7ZJQKN7osJfddMrtjJtYYUk9g/dCpHXs
|
||||
bNh2QSoWah3FdzNGuWd0iRf9+LFxhjAAMo/FS8zFJAJKrFsBdCGTfFUMdsLC0bjr
|
||||
YjiWBuvV72uKf8XIZX5KIZruKdWBBcWukcb21R1UDyFYyXRBsly5XHaIYKZql3km
|
||||
7pV7MKWO0IYgHbHIqGUqPQlzZ/lkunS1jKECgcEA23wHffD6Ou9/x3okPx2AWpTr
|
||||
gh8rgqbyo6hQkBW5Y90Wz824cqaYebZDaBR/xlVx/YwjKkohv8Bde2lpH/ZxRZ1Z
|
||||
5Sk2s6GJ/vU0L9RsJZgCgj4L6Coal1NMxuZtCXAlnOpiCdxSZgfqbshbTVz30KsG
|
||||
ZJG361Cua1ScdAHxlZBxT52/1Sm0zRC2hnxL7h4qo7Idmtzs40LAJvYOKekR0pPN
|
||||
oWeJfra7vgx/jVNvMFWoOoSLpidVO4g+ot4ery6tAoHAdW3rCic1C2zdnmH28Iw+
|
||||
s50l8Lk3mz+I5wgJd1zkzCO0DxZIoWPGA3g7cmCYr6N3KRsZMs4W9NAXgjpFGDkW
|
||||
zYsG3K21BdpvkdjYcFjnPVjlOXB2RIc0vehf9Jl02wXoeCSxVUDEPcaRvWk9RJYx
|
||||
ZpGOchUU7vNkxHURbIJ4yCzuAi9G8/Jp0dsu+kaV5tufF5SjG5WOrzKjaQsCbdN1
|
||||
oqaWMCHRrTvov/Z2C+xwsptFOdN5CSyZzg6hQiI4GMlBAoHAXyb6KINcOEi0YMp3
|
||||
BFXJ23tMTnEs78tozcKeipigcsbaqORK3omS+NEnj+uzKUzJyl4CsMbKstK2tFYS
|
||||
mSTCHqgE3PBtIpsZtEqhgUraR8IK9GPpzZDTTl9ynZgwFTNlWw3RyuyVXF56J+T8
|
||||
kCGJ3hEHCHqT/ZRQyX85BKIDFhA0z4tYKxWVqIFiYBNq56R0X9tMMmMs36mEnF93
|
||||
7Ht6mowxTZQRa7nU0qOgeKh/P7ki4Zus3y+WJ+T9IqahLtlRAoHBAIhqMrcxSAB8
|
||||
RpB9jukJlAnidw2jCMPgrFE8tP0khhVvGrXMldxAUsMKntDIo8dGCnG1KTcWDI0O
|
||||
jepvSPHSsxVLFugL79h0eVIS5z4huW48i9xgU8VlHdgAcgEPIAOFcOw2BCu/s0Vp
|
||||
O+MM/EyUOdo3NsibB3qc/GJI6iNBYS7AljYEVo6rXo5V/MZvZUF4vClen6Obzsre
|
||||
MTTb+4sJjfqleWuvr1XNMeu2mBfXBQkWGZP1byBK0MvD/aQ2PWq92A==
|
||||
-----END RSA PRIVATE KEY-----
|
22
testdata/proxy_protocol.tdir/unbound_server.pem
vendored
Normal file
22
testdata/proxy_protocol.tdir/unbound_server.pem
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDqzCCAhMCFBHWXeQ6ZIa9QcQbXLFfC6tj+KA+MA0GCSqGSIb3DQEBCwUAMBIx
|
||||
EDAOBgNVBAMMB3VuYm91bmQwHhcNMjAwNzA4MTMzMjI5WhcNNDAwMzI1MTMzMjI5
|
||||
WjASMRAwDgYDVQQDDAd1bmJvdW5kMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
|
||||
igKCAYEAvjSVSN2QMXudpzukdLCqgg/IOhCX8KYkD0FFFfWcQjgKq5wI0x41iG32
|
||||
a6wbGanre4IX7VxaSPu9kkHfnGgynCk5nwDRedE/FLFhAU78PoT0+NqqGRS7XVQ2
|
||||
4vLmIz9Hqc2Ozx1um1BXBTmIT0UfN2e22I0LWQ6a3seZlEDRj45gnk7Zuh9MDgot
|
||||
aBdm+v1JAbupSf6Zis4VEH3JNdvVGE3O1DHEIeuuz/3BDhpf6WBDH+8KWaBe1ca4
|
||||
TZHr9ThL2gEMEfAQl0wXDwRWRoi3NjNMH+mw0L1rjwThI5GXqNIee7o5FzUReSXZ
|
||||
uTdFMyGe3Owcx+XoYnwi6cplSNoGsDBu4B9bKKglR9YleJVw4L4Xi8xPq6O9UPj4
|
||||
+nypHk/DOoC7DIM3ufN0yxPBsFo5TVowxfhdjZXJbbftd2TZv7AH8+XLA5UoZgRz
|
||||
XgzECelXSCTBFlMTnT48LfA9pMLydyjAz2UdPHs5Iv+TK5nnI+aJoeaP7kFZSngx
|
||||
dy1+A/bNAgMBAAEwDQYJKoZIhvcNAQELBQADggGBABunf93MKaCUHiZgnoOTinsW
|
||||
84/EgInrgtKzAyH+BhnKkJOhhR0kkIAx5d9BpDlaSiRTACFon9moWCgDIIsK/Ar7
|
||||
JE0Kln9cV//wiiNoFU0O4mnzyGUIMvlaEX6QHMJJQYvL05+w/3AAcf5XmMJtR5ca
|
||||
fJ8FqvGC34b2WxX9lTQoyT52sRt+1KnQikiMEnEyAdKktMG+MwKsFDdOwDXyZhZg
|
||||
XZhRrfX3/NVJolqB6EahjWIGXDeKuSSKZVtCyib6LskyeMzN5lcRfvubKDdlqFVF
|
||||
qlD7rHBsKhQUWK/IO64mGf7y/de+CgHtED5vDvr/p2uj/9sABATfbrOQR3W/Of25
|
||||
sLBj4OEfrJ7lX8hQgFaxkMI3x6VFT3W8dTCp7xnQgb6bgROWB5fNEZ9jk/gjSRmD
|
||||
yIU+r0UbKe5kBk/CmZVFXL2TyJ92V5NYEQh8V4DGy19qZ6u/XKYyNJL4ocs35GGe
|
||||
CA8SBuyrmdhx38h1RHErR2Skzadi1S7MwGf1y431fQ==
|
||||
-----END CERTIFICATE-----
|
@ -786,6 +786,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
||||
else S_SIZET_NONZERO("pad-responses-block-size:", pad_responses_block_size)
|
||||
else S_YNO("pad-queries:", pad_queries)
|
||||
else S_SIZET_NONZERO("pad-queries-block-size:", pad_queries_block_size)
|
||||
else S_STRLIST("proxy-protocol-port:", proxy_protocol_port)
|
||||
#ifdef USE_IPSECMOD
|
||||
else S_YNO("ipsecmod-enabled:", ipsecmod_enabled)
|
||||
else S_YNO("ipsecmod-ignore-bogus:", ipsecmod_ignore_bogus)
|
||||
@ -1262,6 +1263,7 @@ config_get_option(struct config_file* cfg, const char* opt,
|
||||
else O_YNO(opt, "pad-queries", pad_queries)
|
||||
else O_DEC(opt, "pad-queries-block-size", pad_queries_block_size)
|
||||
else O_LS2(opt, "edns-client-strings", edns_client_strings)
|
||||
else O_LST(opt, "proxy-protocol-port", proxy_protocol_port)
|
||||
#ifdef USE_IPSECMOD
|
||||
else O_YNO(opt, "ipsecmod-enabled", ipsecmod_enabled)
|
||||
else O_YNO(opt, "ipsecmod-ignore-bogus", ipsecmod_ignore_bogus)
|
||||
@ -1642,6 +1644,7 @@ config_delete(struct config_file* cfg)
|
||||
config_delstrlist(cfg->python_script);
|
||||
config_delstrlist(cfg->dynlib_file);
|
||||
config_deldblstrlist(cfg->edns_client_strings);
|
||||
config_delstrlist(cfg->proxy_protocol_port);
|
||||
#ifdef USE_IPSECMOD
|
||||
free(cfg->ipsecmod_hook);
|
||||
config_delstrlist(cfg->ipsecmod_whitelist);
|
||||
@ -2624,3 +2627,35 @@ int cfg_has_https(struct config_file* cfg)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** see if interface is PROXYv2, its port number == the proxy port number */
|
||||
int
|
||||
if_is_pp2(const char* ifname, const char* port,
|
||||
struct config_strlist* proxy_protocol_port)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
char* p = strchr(ifname, '@');
|
||||
for(s = proxy_protocol_port; s; s = s->next) {
|
||||
if(p && atoi(p+1) == atoi(s->str))
|
||||
return 1;
|
||||
if(!p && atoi(port) == atoi(s->str))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** see if interface is DNSCRYPT, its port number == the dnscrypt port number */
|
||||
int
|
||||
if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port)
|
||||
{
|
||||
#ifdef USE_DNSCRYPT
|
||||
return ((strchr(ifname, '@') &&
|
||||
atoi(strchr(ifname, '@')+1) == dnscrypt_port) ||
|
||||
(!strchr(ifname, '@') && atoi(port) == dnscrypt_port));
|
||||
#else
|
||||
(void)ifname;
|
||||
(void)port;
|
||||
(void)dnscrypt_port;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -114,6 +114,8 @@ struct config_file {
|
||||
int do_tcp_keepalive;
|
||||
/** tcp keepalive timeout, in msec */
|
||||
int tcp_keepalive_timeout;
|
||||
/** proxy protocol ports */
|
||||
struct config_strlist* proxy_protocol_port;
|
||||
|
||||
/** private key file for dnstcp-ssl service (enabled if not NULL) */
|
||||
char* ssl_service_key;
|
||||
@ -1322,6 +1324,12 @@ int if_is_https(const char* ifname, const char* port, int https_port);
|
||||
*/
|
||||
int cfg_has_https(struct config_file* cfg);
|
||||
|
||||
/** see if interface is PROXYv2, its port number == the proxy port number */
|
||||
int if_is_pp2(const char* ifname, const char* port,
|
||||
struct config_strlist* proxy_protocol_port);
|
||||
|
||||
/** see if interface is DNSCRYPT, its port number == the dnscrypt port number */
|
||||
int if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port);
|
||||
#ifdef USE_LINUX_IP_LOCAL_PORT_RANGE
|
||||
#define LINUX_IP_LOCAL_PORT_RANGE_PATH "/proc/sys/net/ipv4/ip_local_port_range"
|
||||
#endif
|
||||
|
5301
util/configlexer.c
5301
util/configlexer.c
File diff suppressed because it is too large
Load Diff
@ -562,6 +562,7 @@ edns-client-string{COLON} { YDVAR(2, VAR_EDNS_CLIENT_STRING) }
|
||||
edns-client-string-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) }
|
||||
nsid{COLON} { YDVAR(1, VAR_NSID ) }
|
||||
ede{COLON} { YDVAR(1, VAR_EDE ) }
|
||||
proxy-protocol-port{COLON} { YDVAR(1, VAR_PROXY_PROTOCOL_PORT) }
|
||||
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
|
||||
|
||||
/* Quoted strings. Strip leading and ending quotes */
|
||||
|
3582
util/configparser.c
3582
util/configparser.c
File diff suppressed because it is too large
Load Diff
@ -383,7 +383,8 @@ extern int yydebug;
|
||||
VAR_INTERFACE_VIEW = 584, /* VAR_INTERFACE_VIEW */
|
||||
VAR_INTERFACE_TAG = 585, /* VAR_INTERFACE_TAG */
|
||||
VAR_INTERFACE_TAG_ACTION = 586, /* VAR_INTERFACE_TAG_ACTION */
|
||||
VAR_INTERFACE_TAG_DATA = 587 /* VAR_INTERFACE_TAG_DATA */
|
||||
VAR_INTERFACE_TAG_DATA = 587, /* VAR_INTERFACE_TAG_DATA */
|
||||
VAR_PROXY_PROTOCOL_PORT = 588 /* VAR_PROXY_PROTOCOL_PORT */
|
||||
};
|
||||
typedef enum yytokentype yytoken_kind_t;
|
||||
#endif
|
||||
@ -722,6 +723,7 @@ extern int yydebug;
|
||||
#define VAR_INTERFACE_TAG 585
|
||||
#define VAR_INTERFACE_TAG_ACTION 586
|
||||
#define VAR_INTERFACE_TAG_DATA 587
|
||||
#define VAR_PROXY_PROTOCOL_PORT 588
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
@ -731,7 +733,7 @@ union YYSTYPE
|
||||
|
||||
char* str;
|
||||
|
||||
#line 735 "util/configparser.h"
|
||||
#line 737 "util/configparser.h"
|
||||
|
||||
};
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
|
@ -193,6 +193,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
%token VAR_RPZ_SIGNAL_NXDOMAIN_RA VAR_INTERFACE_AUTOMATIC_PORTS VAR_EDE
|
||||
%token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG
|
||||
%token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA
|
||||
%token VAR_PROXY_PROTOCOL_PORT
|
||||
|
||||
%%
|
||||
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
|
||||
@ -320,8 +321,8 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||
server_edns_client_string_opcode | server_nsid |
|
||||
server_zonemd_permissive_mode | server_max_reuse_tcp_queries |
|
||||
server_tcp_reuse_timeout | server_tcp_auth_query_timeout |
|
||||
server_interface_automatic_ports | server_ede
|
||||
|
||||
server_interface_automatic_ports | server_ede |
|
||||
server_proxy_protocol_port
|
||||
;
|
||||
stubstart: VAR_STUB_ZONE
|
||||
{
|
||||
@ -2824,6 +2825,13 @@ server_ede: VAR_EDE STRING_ARG
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_proxy_protocol_port: VAR_PROXY_PROTOCOL_PORT STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_proxy_protocol_port:%s)\n", $2));
|
||||
if(!cfg_strlist_insert(&cfg_parser->cfg->proxy_protocol_port, $2))
|
||||
yyerror("out of memory");
|
||||
}
|
||||
;
|
||||
stub_name: VAR_NAME STRING_ARG
|
||||
{
|
||||
OUTYY(("P(name:%s)\n", $2));
|
||||
|
587
util/netevent.c
587
util/netevent.c
@ -45,6 +45,7 @@
|
||||
#include "util/net_help.h"
|
||||
#include "util/tcp_conn_limit.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "util/proxy_protocol.h"
|
||||
#include "sldns/pkthdr.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "sldns/str2wire.h"
|
||||
@ -755,6 +756,67 @@ static int udp_recv_needs_log(int err)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Parses the PROXYv2 header from buf and updates the comm_reply struct.
|
||||
* Returns 1 on success, 0 on failure. */
|
||||
static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
|
||||
int stream) {
|
||||
size_t size;
|
||||
struct pp2_header *header = pp2_read_header(buf);
|
||||
if(header == NULL) return 0;
|
||||
size = PP2_HEADER_SIZE + ntohs(header->len);
|
||||
if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
|
||||
/* A connection from the proxy itself.
|
||||
* No need to do anything with addresses. */
|
||||
goto done;
|
||||
}
|
||||
if(header->fam_prot == 0x00) {
|
||||
/* Unspecified family and protocol. This could be used for
|
||||
* health checks by proxies.
|
||||
* No need to do anything with addresses. */
|
||||
goto done;
|
||||
}
|
||||
/* Read the proxied address */
|
||||
switch(header->fam_prot) {
|
||||
case 0x11: /* AF_INET|STREAM */
|
||||
case 0x12: /* AF_INET|DGRAM */
|
||||
{
|
||||
struct sockaddr_in* addr =
|
||||
(struct sockaddr_in*)&rep->client_addr;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = header->addr.addr4.src_addr;
|
||||
addr->sin_port = header->addr.addr4.src_port;
|
||||
rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
}
|
||||
/* Ignore the destination address; it should be us. */
|
||||
break;
|
||||
case 0x21: /* AF_INET6|STREAM */
|
||||
case 0x22: /* AF_INET6|DGRAM */
|
||||
{
|
||||
struct sockaddr_in6* addr =
|
||||
(struct sockaddr_in6*)&rep->client_addr;
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
addr->sin6_family = AF_INET6;
|
||||
memcpy(&addr->sin6_addr,
|
||||
header->addr.addr6.src_addr, 16);
|
||||
addr->sin6_port = header->addr.addr6.src_port;
|
||||
rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
}
|
||||
/* Ignore the destination address; it should be us. */
|
||||
break;
|
||||
}
|
||||
rep->is_proxied = 1;
|
||||
done:
|
||||
if(!stream) {
|
||||
/* We are reading a whole packet;
|
||||
* Move the rest of the data to overwrite the PROXYv2 header */
|
||||
/* XXX can we do better to avoid memmove? */
|
||||
memmove(header, ((void*)header)+size,
|
||||
sldns_buffer_limit(buf)-size);
|
||||
sldns_buffer_set_limit(buf, sldns_buffer_limit(buf)-size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
comm_point_udp_ancil_callback(int fd, short event, void* arg)
|
||||
{
|
||||
@ -781,11 +843,11 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
|
||||
ub_comm_base_now(rep.c->ev->base);
|
||||
for(i=0; i<NUM_UDP_PER_SELECT; i++) {
|
||||
sldns_buffer_clear(rep.c->buffer);
|
||||
rep.addrlen = (socklen_t)sizeof(rep.addr);
|
||||
rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
|
||||
log_assert(fd != -1);
|
||||
log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
|
||||
msg.msg_name = &rep.addr;
|
||||
msg.msg_namelen = (socklen_t)sizeof(rep.addr);
|
||||
msg.msg_name = &rep.remote_addr;
|
||||
msg.msg_namelen = (socklen_t)sizeof(rep.remote_addr);
|
||||
iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
|
||||
iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
|
||||
msg.msg_iov = iov;
|
||||
@ -803,10 +865,11 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
|
||||
}
|
||||
return;
|
||||
}
|
||||
rep.addrlen = msg.msg_namelen;
|
||||
rep.remote_addrlen = msg.msg_namelen;
|
||||
sldns_buffer_skip(rep.c->buffer, rcv);
|
||||
sldns_buffer_flip(rep.c->buffer);
|
||||
rep.srctype = 0;
|
||||
rep.is_proxied = 0;
|
||||
#ifndef S_SPLINT_S
|
||||
for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
@ -836,11 +899,24 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
|
||||
if(verbosity >= VERB_ALGO)
|
||||
p_ancil("receive_udp on interface", &rep);
|
||||
#endif /* S_SPLINT_S */
|
||||
|
||||
if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
|
||||
&rep, 0)) {
|
||||
log_err("proxy_protocol: could not consume PROXYv2 header");
|
||||
return;
|
||||
}
|
||||
if(!rep.is_proxied) {
|
||||
rep.client_addrlen = rep.remote_addrlen;
|
||||
memmove(&rep.client_addr, &rep.remote_addr,
|
||||
rep.remote_addrlen);
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
|
||||
if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
|
||||
/* send back immediate reply */
|
||||
(void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
|
||||
(struct sockaddr*)&rep.addr, rep.addrlen, &rep);
|
||||
(struct sockaddr*)&rep.remote_addr,
|
||||
rep.remote_addrlen, &rep);
|
||||
}
|
||||
if(!rep.c || rep.c->fd == -1) /* commpoint closed */
|
||||
break;
|
||||
@ -871,12 +947,12 @@ comm_point_udp_callback(int fd, short event, void* arg)
|
||||
ub_comm_base_now(rep.c->ev->base);
|
||||
for(i=0; i<NUM_UDP_PER_SELECT; i++) {
|
||||
sldns_buffer_clear(rep.c->buffer);
|
||||
rep.addrlen = (socklen_t)sizeof(rep.addr);
|
||||
rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
|
||||
log_assert(fd != -1);
|
||||
log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
|
||||
rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
|
||||
sldns_buffer_remaining(rep.c->buffer), MSG_DONTWAIT,
|
||||
(struct sockaddr*)&rep.addr, &rep.addrlen);
|
||||
(struct sockaddr*)&rep.remote_addr, &rep.remote_addrlen);
|
||||
if(rcv == -1) {
|
||||
#ifndef USE_WINSOCK
|
||||
if(errno != EAGAIN && errno != EINTR
|
||||
@ -896,6 +972,19 @@ comm_point_udp_callback(int fd, short event, void* arg)
|
||||
sldns_buffer_skip(rep.c->buffer, rcv);
|
||||
sldns_buffer_flip(rep.c->buffer);
|
||||
rep.srctype = 0;
|
||||
rep.is_proxied = 0;
|
||||
|
||||
if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
|
||||
&rep, 0)) {
|
||||
log_err("proxy_protocol: could not consume PROXYv2 header");
|
||||
return;
|
||||
}
|
||||
if(!rep.is_proxied) {
|
||||
rep.client_addrlen = rep.remote_addrlen;
|
||||
memmove(&rep.client_addr, &rep.remote_addr,
|
||||
rep.remote_addrlen);
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
|
||||
if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
|
||||
/* send back immediate reply */
|
||||
@ -905,7 +994,8 @@ comm_point_udp_callback(int fd, short event, void* arg)
|
||||
buffer = rep.c->buffer;
|
||||
#endif
|
||||
(void)comm_point_send_udp_msg(rep.c, buffer,
|
||||
(struct sockaddr*)&rep.addr, rep.addrlen, 0);
|
||||
(struct sockaddr*)&rep.remote_addr,
|
||||
rep.remote_addrlen, 0);
|
||||
}
|
||||
if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
|
||||
another UDP port. Note rep.c cannot be reused with TCP fd. */
|
||||
@ -1221,10 +1311,16 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
|
||||
}
|
||||
log_assert(fd != -1);
|
||||
(void)fd;
|
||||
new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
|
||||
&c_hdl->repinfo.addrlen);
|
||||
new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.remote_addr,
|
||||
&c_hdl->repinfo.remote_addrlen);
|
||||
if(new_fd == -1)
|
||||
return;
|
||||
/* Copy remote_address to client_address.
|
||||
* Simplest way/time for streams to do that. */
|
||||
c_hdl->repinfo.client_addrlen = c_hdl->repinfo.remote_addrlen;
|
||||
memmove(&c_hdl->repinfo.client_addr,
|
||||
&c_hdl->repinfo.remote_addr,
|
||||
c_hdl->repinfo.remote_addrlen);
|
||||
if(c->ssl) {
|
||||
c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
|
||||
if(!c_hdl->ssl) {
|
||||
@ -1276,6 +1372,7 @@ reclaim_tcp_handler(struct comm_point* c)
|
||||
c->tcp_more_read_again = NULL;
|
||||
c->tcp_more_write_again = NULL;
|
||||
c->tcp_byte_count = 0;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
sldns_buffer_clear(c->buffer);
|
||||
}
|
||||
|
||||
@ -1407,8 +1504,8 @@ ssl_handshake(struct comm_point* c)
|
||||
return 0; /* silence reset by peer */
|
||||
#endif
|
||||
if(!tcp_connect_errno_needs_log(
|
||||
(struct sockaddr*)&c->repinfo.addr,
|
||||
c->repinfo.addrlen))
|
||||
(struct sockaddr*)&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen))
|
||||
return 0; /* silence connect failures that
|
||||
show up because after connect this is the
|
||||
first system call that accesses the socket */
|
||||
@ -1420,8 +1517,9 @@ ssl_handshake(struct comm_point* c)
|
||||
unsigned long err = ERR_get_error();
|
||||
if(!squelch_err_ssl_handshake(err)) {
|
||||
log_crypto_err_code("ssl handshake failed", err);
|
||||
log_addr(VERB_OPS, "ssl handshake failed", &c->repinfo.addr,
|
||||
c->repinfo.addrlen);
|
||||
log_addr(VERB_OPS, "ssl handshake failed",
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1438,7 +1536,8 @@ ssl_handshake(struct comm_point* c)
|
||||
if(!x) {
|
||||
log_addr(VERB_ALGO, "SSL connection failed: "
|
||||
"no certificate",
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
log_cert(VERB_ALGO, "peer certificate", x);
|
||||
@ -1448,13 +1547,13 @@ ssl_handshake(struct comm_point* c)
|
||||
snprintf(buf, sizeof(buf), "SSL connection "
|
||||
"to %s authenticated",
|
||||
SSL_get0_peername(c->ssl));
|
||||
log_addr(VERB_ALGO, buf, &c->repinfo.addr,
|
||||
c->repinfo.addrlen);
|
||||
log_addr(VERB_ALGO, buf, &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
} else {
|
||||
#endif
|
||||
log_addr(VERB_ALGO, "SSL connection "
|
||||
"authenticated", &c->repinfo.addr,
|
||||
c->repinfo.addrlen);
|
||||
"authenticated", &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
#ifdef HAVE_SSL_GET0_PEERNAME
|
||||
}
|
||||
#endif
|
||||
@ -1471,14 +1570,15 @@ ssl_handshake(struct comm_point* c)
|
||||
}
|
||||
log_addr(VERB_ALGO, "SSL connection failed: "
|
||||
"failed to authenticate",
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* unauthenticated, the verify peer flag was not set
|
||||
* in c->ssl when the ssl object was created from ssl_ctx */
|
||||
log_addr(VERB_ALGO, "SSL connection", &c->repinfo.addr,
|
||||
c->repinfo.addrlen);
|
||||
log_addr(VERB_ALGO, "SSL connection", &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL_GET0_ALPN_SELECTED
|
||||
@ -1519,6 +1619,139 @@ ssl_handle_read(struct comm_point* c)
|
||||
if(c->ssl_shake_state != comm_ssl_shake_none)
|
||||
return 1;
|
||||
}
|
||||
if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
|
||||
struct pp2_header* header = NULL;
|
||||
size_t want_read_size = 0;
|
||||
size_t current_read_size = 0;
|
||||
if(c->pp2_header_state == pp2_header_none) {
|
||||
want_read_size = PP2_HEADER_SIZE;
|
||||
if(sldns_buffer_remaining(c->buffer)<want_read_size) {
|
||||
log_err_addr("proxy_protocol: not enough "
|
||||
"buffer size to read PROXYv2 header", "",
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "proxy_protocol: reading fixed "
|
||||
"part of PROXYv2 header (len %lu)",
|
||||
want_read_size);
|
||||
current_read_size = want_read_size;
|
||||
if(c->tcp_byte_count < current_read_size) {
|
||||
ERR_clear_error();
|
||||
if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
|
||||
c->buffer, c->tcp_byte_count),
|
||||
current_read_size -
|
||||
c->tcp_byte_count)) <= 0) {
|
||||
int want = SSL_get_error(c->ssl, r);
|
||||
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||
if(c->tcp_req_info)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0; /* shutdown, closed */
|
||||
} else if(want == SSL_ERROR_WANT_READ) {
|
||||
#ifdef USE_WINSOCK
|
||||
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
|
||||
#endif
|
||||
return 1; /* read more later */
|
||||
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||
c->ssl_shake_state = comm_ssl_shake_hs_write;
|
||||
comm_point_listen_for_rw(c, 0, 1);
|
||||
return 1;
|
||||
} else if(want == SSL_ERROR_SYSCALL) {
|
||||
#ifdef ECONNRESET
|
||||
if(errno == ECONNRESET && verbosity < 2)
|
||||
return 0; /* silence reset by peer */
|
||||
#endif
|
||||
if(errno != 0)
|
||||
log_err("SSL_read syscall: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
log_crypto_err("could not SSL_read");
|
||||
return 0;
|
||||
}
|
||||
c->tcp_byte_count += r;
|
||||
if(c->tcp_byte_count != current_read_size) return 1;
|
||||
c->pp2_header_state = pp2_header_init;
|
||||
}
|
||||
}
|
||||
if(c->pp2_header_state == pp2_header_init) {
|
||||
header = pp2_read_header(c->buffer);
|
||||
if(!header) {
|
||||
log_err("proxy_protocol: could not parse "
|
||||
"PROXYv2 header");
|
||||
return 0;
|
||||
}
|
||||
want_read_size = ntohs(header->len);
|
||||
if(sldns_buffer_remaining(c->buffer) <
|
||||
PP2_HEADER_SIZE + want_read_size) {
|
||||
log_err_addr("proxy_protocol: not enough "
|
||||
"buffer size to read PROXYv2 header", "",
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "proxy_protocol: reading variable "
|
||||
"part of PROXYv2 header (len %lu)",
|
||||
want_read_size);
|
||||
current_read_size = PP2_HEADER_SIZE + want_read_size;
|
||||
if(c->tcp_byte_count < current_read_size) {
|
||||
ERR_clear_error();
|
||||
if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
|
||||
c->buffer, c->tcp_byte_count),
|
||||
current_read_size -
|
||||
c->tcp_byte_count)) <= 0) {
|
||||
int want = SSL_get_error(c->ssl, r);
|
||||
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||
if(c->tcp_req_info)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0; /* shutdown, closed */
|
||||
} else if(want == SSL_ERROR_WANT_READ) {
|
||||
#ifdef USE_WINSOCK
|
||||
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
|
||||
#endif
|
||||
return 1; /* read more later */
|
||||
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||
c->ssl_shake_state = comm_ssl_shake_hs_write;
|
||||
comm_point_listen_for_rw(c, 0, 1);
|
||||
return 1;
|
||||
} else if(want == SSL_ERROR_SYSCALL) {
|
||||
#ifdef ECONNRESET
|
||||
if(errno == ECONNRESET && verbosity < 2)
|
||||
return 0; /* silence reset by peer */
|
||||
#endif
|
||||
if(errno != 0)
|
||||
log_err("SSL_read syscall: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
log_crypto_err("could not SSL_read");
|
||||
return 0;
|
||||
}
|
||||
c->tcp_byte_count += r;
|
||||
if(c->tcp_byte_count != current_read_size) return 1;
|
||||
c->pp2_header_state = pp2_header_done;
|
||||
}
|
||||
}
|
||||
if(c->pp2_header_state != pp2_header_done || !header) {
|
||||
log_err_addr("proxy_protocol: wrong state for the "
|
||||
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
|
||||
log_err_addr("proxy_protocol: could not consume "
|
||||
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "proxy_protocol: successful read of "
|
||||
"PROXYv2 header");
|
||||
/* Clear and reset the buffer to read the following
|
||||
* DNS packet(s). */
|
||||
sldns_buffer_clear(c->buffer);
|
||||
c->tcp_byte_count = 0;
|
||||
return 1;
|
||||
}
|
||||
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||
/* read length bytes */
|
||||
ERR_clear_error();
|
||||
@ -1778,7 +2011,8 @@ ssl_handle_it(struct comm_point* c, int is_write)
|
||||
return ssl_handle_write(c);
|
||||
}
|
||||
|
||||
/** Handle tcp reading callback.
|
||||
/**
|
||||
* Handle tcp reading callback.
|
||||
* @param fd: file descriptor of socket.
|
||||
* @param c: comm point to read from into buffer.
|
||||
* @param short_ok: if true, very short packets are OK (for comm_local).
|
||||
@ -1788,6 +2022,7 @@ static int
|
||||
comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||
{
|
||||
ssize_t r;
|
||||
int recv_initial = 0;
|
||||
log_assert(c->type == comm_tcp || c->type == comm_local);
|
||||
if(c->ssl)
|
||||
return ssl_handle_it(c, 0);
|
||||
@ -1795,6 +2030,96 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||
return 0;
|
||||
|
||||
log_assert(fd != -1);
|
||||
if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
|
||||
struct pp2_header* header = NULL;
|
||||
size_t want_read_size = 0;
|
||||
size_t current_read_size = 0;
|
||||
if(c->pp2_header_state == pp2_header_none) {
|
||||
want_read_size = PP2_HEADER_SIZE;
|
||||
if(sldns_buffer_remaining(c->buffer)<want_read_size) {
|
||||
log_err_addr("proxy_protocol: not enough "
|
||||
"buffer size to read PROXYv2 header", "",
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "proxy_protocol: reading fixed "
|
||||
"part of PROXYv2 header (len %lu)",
|
||||
want_read_size);
|
||||
current_read_size = want_read_size;
|
||||
if(c->tcp_byte_count < current_read_size) {
|
||||
r = recv(fd, (void*)sldns_buffer_at(c->buffer,
|
||||
c->tcp_byte_count),
|
||||
current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
|
||||
if(r == 0) {
|
||||
if(c->tcp_req_info)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0;
|
||||
} else if(r == -1) {
|
||||
goto recv_error_initial;
|
||||
}
|
||||
c->tcp_byte_count += r;
|
||||
if(c->tcp_byte_count != current_read_size) return 1;
|
||||
c->pp2_header_state = pp2_header_init;
|
||||
}
|
||||
}
|
||||
if(c->pp2_header_state == pp2_header_init) {
|
||||
header = pp2_read_header(c->buffer);
|
||||
if(!header) {
|
||||
log_err("proxy_protocol: could not parse "
|
||||
"PROXYv2 header");
|
||||
return 0;
|
||||
}
|
||||
want_read_size = ntohs(header->len);
|
||||
if(sldns_buffer_remaining(c->buffer) <
|
||||
PP2_HEADER_SIZE + want_read_size) {
|
||||
log_err_addr("proxy_protocol: not enough "
|
||||
"buffer size to read PROXYv2 header", "",
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "proxy_protocol: reading variable "
|
||||
"part of PROXYv2 header (len %lu)",
|
||||
want_read_size);
|
||||
current_read_size = PP2_HEADER_SIZE + want_read_size;
|
||||
if(c->tcp_byte_count < current_read_size) {
|
||||
r = recv(fd, (void*)sldns_buffer_at(c->buffer,
|
||||
c->tcp_byte_count),
|
||||
current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
|
||||
if(r == 0) {
|
||||
if(c->tcp_req_info)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0;
|
||||
} else if(r == -1) {
|
||||
goto recv_error;
|
||||
}
|
||||
c->tcp_byte_count += r;
|
||||
if(c->tcp_byte_count != current_read_size) return 1;
|
||||
c->pp2_header_state = pp2_header_done;
|
||||
}
|
||||
}
|
||||
if(c->pp2_header_state != pp2_header_done || !header) {
|
||||
log_err_addr("proxy_protocol: wrong state for the "
|
||||
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
|
||||
log_err_addr("proxy_protocol: could not consume "
|
||||
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "proxy_protocol: successful read of "
|
||||
"PROXYv2 header");
|
||||
/* Clear and reset the buffer to read the following
|
||||
* DNS packet(s). */
|
||||
sldns_buffer_clear(c->buffer);
|
||||
c->tcp_byte_count = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||
/* read length bytes */
|
||||
r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
|
||||
@ -1804,9 +2129,54 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0;
|
||||
} else if(r == -1) {
|
||||
if(c->pp2_enabled) goto recv_error;
|
||||
goto recv_error_initial;
|
||||
}
|
||||
c->tcp_byte_count += r;
|
||||
if(c->tcp_byte_count != sizeof(uint16_t))
|
||||
return 1;
|
||||
if(sldns_buffer_read_u16_at(c->buffer, 0) >
|
||||
sldns_buffer_capacity(c->buffer)) {
|
||||
verbose(VERB_QUERY, "tcp: dropped larger than buffer");
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_set_limit(c->buffer,
|
||||
sldns_buffer_read_u16_at(c->buffer, 0));
|
||||
if(!short_ok &&
|
||||
sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
|
||||
verbose(VERB_QUERY, "tcp: dropped bogus too short.");
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "Reading tcp query of length %d",
|
||||
(int)sldns_buffer_limit(c->buffer));
|
||||
}
|
||||
|
||||
if(sldns_buffer_remaining(c->buffer) == 0)
|
||||
log_err("in comm_point_tcp_handle_read buffer_remaining is "
|
||||
"not > 0 as expected, continuing with (harmless) 0 "
|
||||
"length recv");
|
||||
r = recv(fd, (void*)sldns_buffer_current(c->buffer),
|
||||
sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
|
||||
if(r == 0) {
|
||||
if(c->tcp_req_info)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0;
|
||||
} else if(r == -1) {
|
||||
goto recv_error;
|
||||
}
|
||||
sldns_buffer_skip(c->buffer, r);
|
||||
if(sldns_buffer_remaining(c->buffer) <= 0) {
|
||||
tcp_callback_reader(c);
|
||||
}
|
||||
return 1;
|
||||
|
||||
recv_error_initial:
|
||||
recv_initial = 1;
|
||||
recv_error:
|
||||
#ifndef USE_WINSOCK
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
return 1;
|
||||
if(recv_initial) {
|
||||
#ifdef ECONNRESET
|
||||
if(errno == ECONNRESET && verbosity < 2)
|
||||
return 0; /* silence reset by peer */
|
||||
@ -1837,12 +2207,19 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||
#endif
|
||||
#ifdef ENOTCONN
|
||||
if(errno == ENOTCONN) {
|
||||
log_err_addr("read (in tcp s) failed and this could be because TCP Fast Open is enabled [--disable-tfo-client --disable-tfo-server] but does not work", sock_strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
log_err_addr("read (in tcp s) failed and this "
|
||||
"could be because TCP Fast Open is "
|
||||
"enabled [--disable-tfo-client "
|
||||
"--disable-tfo-server] but does not "
|
||||
"work", sock_strerror(errno),
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else /* USE_WINSOCK */
|
||||
if(recv_initial) {
|
||||
if(WSAGetLastError() == WSAECONNREFUSED && verbosity < 2)
|
||||
return 0;
|
||||
if(WSAGetLastError() == WSAEHOSTDOWN && verbosity < 2)
|
||||
@ -1853,6 +2230,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||
return 0;
|
||||
if(WSAGetLastError() == WSAENETUNREACH && verbosity < 2)
|
||||
return 0;
|
||||
}
|
||||
if(WSAGetLastError() == WSAECONNRESET)
|
||||
return 0;
|
||||
if(WSAGetLastError() == WSAEINPROGRESS)
|
||||
@ -1864,60 +2242,9 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||
}
|
||||
#endif
|
||||
log_err_addr("read (in tcp s)", sock_strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
c->tcp_byte_count += r;
|
||||
if(c->tcp_byte_count != sizeof(uint16_t))
|
||||
return 1;
|
||||
if(sldns_buffer_read_u16_at(c->buffer, 0) >
|
||||
sldns_buffer_capacity(c->buffer)) {
|
||||
verbose(VERB_QUERY, "tcp: dropped larger than buffer");
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_set_limit(c->buffer,
|
||||
sldns_buffer_read_u16_at(c->buffer, 0));
|
||||
if(!short_ok &&
|
||||
sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
|
||||
verbose(VERB_QUERY, "tcp: dropped bogus too short.");
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "Reading tcp query of length %d",
|
||||
(int)sldns_buffer_limit(c->buffer));
|
||||
}
|
||||
|
||||
if(sldns_buffer_remaining(c->buffer) == 0)
|
||||
log_err("in comm_point_tcp_handle_read buffer_remaining is not > 0 as expected, continuing with (harmless) 0 length recv");
|
||||
r = recv(fd, (void*)sldns_buffer_current(c->buffer),
|
||||
sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
|
||||
if(r == 0) {
|
||||
if(c->tcp_req_info)
|
||||
return tcp_req_info_handle_read_close(c->tcp_req_info);
|
||||
return 0;
|
||||
} else if(r == -1) {
|
||||
#ifndef USE_WINSOCK
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
return 1;
|
||||
#else /* USE_WINSOCK */
|
||||
if(WSAGetLastError() == WSAECONNRESET)
|
||||
return 0;
|
||||
if(WSAGetLastError() == WSAEINPROGRESS)
|
||||
return 1;
|
||||
if(WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
log_err_addr("read (in tcp r)", sock_strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_skip(c->buffer, r);
|
||||
if(sldns_buffer_remaining(c->buffer) <= 0) {
|
||||
tcp_callback_reader(c);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tcp writing callback.
|
||||
@ -1962,7 +2289,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
return 0; /* silence lots of chatter in the logs */
|
||||
else if(error != 0) {
|
||||
log_err_addr("tcp connect", strerror(error),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
#else /* USE_WINSOCK */
|
||||
/* examine error */
|
||||
if(error == WSAEINPROGRESS)
|
||||
@ -1974,7 +2302,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
return 0;
|
||||
else if(error != 0) {
|
||||
log_err_addr("tcp connect", wsa_strerror(error),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
#endif /* USE_WINSOCK */
|
||||
return 0;
|
||||
}
|
||||
@ -2006,8 +2335,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
iov[1].iov_len = sldns_buffer_limit(buffer);
|
||||
}
|
||||
log_assert(iov[0].iov_len > 0);
|
||||
msg.msg_name = &c->repinfo.addr;
|
||||
msg.msg_namelen = c->repinfo.addrlen;
|
||||
msg.msg_name = &c->repinfo.remote_addr;
|
||||
msg.msg_namelen = c->repinfo.remote_addrlen;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 2;
|
||||
r = sendmsg(fd, &msg, MSG_FASTOPEN);
|
||||
@ -2033,14 +2362,16 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
if(verbosity < 2)
|
||||
return 0; /* silence lots of chatter in the logs */
|
||||
log_err_addr("tcp sendmsg", strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "tcp sendmsg for fastopen failed (with %s), try normal connect", strerror(errno));
|
||||
/* fallthrough to nonFASTOPEN
|
||||
* (MSG_FASTOPEN on Linux 3 produces EPIPE)
|
||||
* we need to perform connect() */
|
||||
if(connect(fd, (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen) == -1) {
|
||||
if(connect(fd, (struct sockaddr *)&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen) == -1) {
|
||||
#ifdef EINPROGRESS
|
||||
if(errno == EINPROGRESS)
|
||||
return 1; /* wait until connect done*/
|
||||
@ -2051,9 +2382,12 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
return 1; /* wait until connect done*/
|
||||
#endif
|
||||
if(tcp_connect_errno_needs_log(
|
||||
(struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen)) {
|
||||
(struct sockaddr *)&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen)) {
|
||||
log_err_addr("outgoing tcp: connect after EPIPE for fastopen",
|
||||
strerror(errno), &c->repinfo.addr, c->repinfo.addrlen);
|
||||
strerror(errno),
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2118,10 +2452,12 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
#endif
|
||||
# ifdef HAVE_WRITEV
|
||||
log_err_addr("tcp writev", strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
# else /* HAVE_WRITEV */
|
||||
log_err_addr("tcp send s", strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
# endif /* HAVE_WRITEV */
|
||||
#else
|
||||
if(WSAGetLastError() == WSAENOTCONN)
|
||||
@ -2137,7 +2473,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
return 0; /* silence reset by peer */
|
||||
log_err_addr("tcp send s",
|
||||
wsa_strerror(WSAGetLastError()),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@ -2185,7 +2522,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
return 0; /* silence reset by peer */
|
||||
#endif
|
||||
log_err_addr("tcp send r", sock_strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
if(c->tcp_write_and_read) {
|
||||
@ -2449,7 +2787,7 @@ http_read_more(int fd, struct comm_point* c)
|
||||
}
|
||||
#endif
|
||||
log_err_addr("read (in http r)", sock_strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "http read more skip to %d + %d",
|
||||
@ -2881,8 +3219,8 @@ ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf,
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
#endif
|
||||
log_err_addr("could not http2 recv: %s", strerror(errno),
|
||||
&h2_session->c->repinfo.addr,
|
||||
h2_session->c->repinfo.addrlen);
|
||||
&h2_session->c->repinfo.remote_addr,
|
||||
h2_session->c->repinfo.remote_addrlen);
|
||||
#else /* USE_WINSOCK */
|
||||
if(WSAGetLastError() == WSAECONNRESET)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
@ -2895,8 +3233,8 @@ ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf,
|
||||
}
|
||||
log_err_addr("could not http2 recv: %s",
|
||||
wsa_strerror(WSAGetLastError()),
|
||||
&h2_session->c->repinfo.addr,
|
||||
h2_session->c->repinfo.addrlen);
|
||||
&h2_session->c->repinfo.remote_addr,
|
||||
h2_session->c->repinfo.remote_addrlen);
|
||||
#endif
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
@ -2918,8 +3256,8 @@ comm_point_http2_handle_read(int ATTR_UNUSED(fd), struct comm_point* c)
|
||||
if(ret != NGHTTP2_ERR_EOF &&
|
||||
ret != NGHTTP2_ERR_CALLBACK_FAILURE) {
|
||||
char a[256];
|
||||
addr_to_str(&c->repinfo.addr, c->repinfo.addrlen,
|
||||
a, sizeof(a));
|
||||
addr_to_str(&c->repinfo.remote_addr,
|
||||
c->repinfo.remote_addrlen, a, sizeof(a));
|
||||
verbose(VERB_QUERY, "http2: session_recv from %s failed, "
|
||||
"error: %s", a, nghttp2_strerror(ret));
|
||||
}
|
||||
@ -3067,7 +3405,7 @@ http_check_connect(int fd, struct comm_point* c)
|
||||
return 0; /* silence lots of chatter in the logs */
|
||||
else if(error != 0) {
|
||||
log_err_addr("http connect", strerror(error),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
|
||||
#else /* USE_WINSOCK */
|
||||
/* examine error */
|
||||
if(error == WSAEINPROGRESS)
|
||||
@ -3079,7 +3417,7 @@ http_check_connect(int fd, struct comm_point* c)
|
||||
return 0;
|
||||
else if(error != 0) {
|
||||
log_err_addr("http connect", wsa_strerror(error),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
|
||||
#endif /* USE_WINSOCK */
|
||||
return 0;
|
||||
}
|
||||
@ -3149,7 +3487,7 @@ http_write_more(int fd, struct comm_point* c)
|
||||
}
|
||||
#endif
|
||||
log_err_addr("http send r", sock_strerror(errno),
|
||||
&c->repinfo.addr, c->repinfo.addrlen);
|
||||
&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_skip(c->buffer, r);
|
||||
@ -3213,8 +3551,8 @@ ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf,
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
#endif
|
||||
log_err_addr("could not http2 write: %s", strerror(errno),
|
||||
&h2_session->c->repinfo.addr,
|
||||
h2_session->c->repinfo.addrlen);
|
||||
&h2_session->c->repinfo.remote_addr,
|
||||
h2_session->c->repinfo.remote_addrlen);
|
||||
#else /* USE_WINSOCK */
|
||||
if(WSAGetLastError() == WSAENOTCONN)
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
@ -3229,8 +3567,8 @@ ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf,
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
log_err_addr("could not http2 write: %s",
|
||||
wsa_strerror(WSAGetLastError()),
|
||||
&h2_session->c->repinfo.addr,
|
||||
h2_session->c->repinfo.addrlen);
|
||||
&h2_session->c->repinfo.remote_addr,
|
||||
h2_session->c->repinfo.remote_addrlen);
|
||||
#endif
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
@ -3410,7 +3748,8 @@ 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, struct unbound_socket* socket)
|
||||
int pp2_enabled, 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));
|
||||
@ -3450,6 +3789,8 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->socket = socket;
|
||||
c->pp2_enabled = pp2_enabled;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
evbits = UB_EV_READ | UB_EV_PERSIST;
|
||||
/* ub_event stuff */
|
||||
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
|
||||
@ -3470,7 +3811,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,
|
||||
sldns_buffer* buffer, int pp2_enabled,
|
||||
comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
|
||||
{
|
||||
struct comm_point* c = (struct comm_point*)calloc(1,
|
||||
@ -3511,6 +3852,8 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd,
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->socket = socket;
|
||||
c->pp2_enabled = pp2_enabled;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
evbits = UB_EV_READ | UB_EV_PERSIST;
|
||||
/* ub_event stuff */
|
||||
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
|
||||
@ -3590,6 +3933,8 @@ comm_point_create_tcp_handler(struct comm_base *base,
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->socket = socket;
|
||||
c->pp2_enabled = parent->pp2_enabled;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
if(spoolbuf) {
|
||||
c->tcp_req_info = tcp_req_info_create(spoolbuf);
|
||||
if(!c->tcp_req_info) {
|
||||
@ -3685,6 +4030,8 @@ comm_point_create_http_handler(struct comm_base *base,
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->socket = socket;
|
||||
c->pp2_enabled = 0;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
|
||||
c->http_min_version = http_version_2;
|
||||
c->http2_stream_max_qbuffer_size = bufsize;
|
||||
@ -3749,7 +4096,8 @@ 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, struct unbound_socket* socket)
|
||||
int pp2_enabled, 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));
|
||||
@ -3800,6 +4148,8 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num,
|
||||
c->callback = NULL;
|
||||
c->cb_arg = NULL;
|
||||
c->socket = socket;
|
||||
c->pp2_enabled = (port_type==listen_type_http?0:pp2_enabled);
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
evbits = UB_EV_READ | UB_EV_PERSIST;
|
||||
/* ub_event stuff */
|
||||
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
|
||||
@ -3892,6 +4242,8 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
|
||||
c->repinfo.c = c;
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->pp2_enabled = 0;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
evbits = UB_EV_PERSIST | UB_EV_WRITE;
|
||||
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
|
||||
comm_point_tcp_handle_callback, c);
|
||||
@ -3958,6 +4310,8 @@ comm_point_create_http_out(struct comm_base *base, size_t bufsize,
|
||||
c->repinfo.c = c;
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->pp2_enabled = 0;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
evbits = UB_EV_PERSIST | UB_EV_WRITE;
|
||||
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
|
||||
comm_point_http_handle_callback, c);
|
||||
@ -4021,6 +4375,8 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
|
||||
#endif
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->pp2_enabled = 0;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
/* ub_event stuff */
|
||||
evbits = UB_EV_PERSIST | UB_EV_READ;
|
||||
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
|
||||
@ -4082,6 +4438,8 @@ comm_point_create_raw(struct comm_base* base, int fd, int writing,
|
||||
#endif
|
||||
c->callback = callback;
|
||||
c->cb_arg = callback_arg;
|
||||
c->pp2_enabled = 0;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
/* ub_event stuff */
|
||||
if(writing)
|
||||
evbits = UB_EV_PERSIST | UB_EV_WRITE;
|
||||
@ -4197,20 +4555,21 @@ comm_point_send_reply(struct comm_reply *repinfo)
|
||||
#endif
|
||||
if(repinfo->c->type == comm_udp) {
|
||||
if(repinfo->srctype)
|
||||
comm_point_send_udp_msg_if(repinfo->c,
|
||||
buffer, (struct sockaddr*)&repinfo->addr,
|
||||
repinfo->addrlen, repinfo);
|
||||
comm_point_send_udp_msg_if(repinfo->c, buffer,
|
||||
(struct sockaddr*)&repinfo->remote_addr,
|
||||
repinfo->remote_addrlen, repinfo);
|
||||
else
|
||||
comm_point_send_udp_msg(repinfo->c, buffer,
|
||||
(struct sockaddr*)&repinfo->addr, repinfo->addrlen, 0);
|
||||
(struct sockaddr*)&repinfo->remote_addr,
|
||||
repinfo->remote_addrlen, 0);
|
||||
#ifdef USE_DNSTAP
|
||||
/*
|
||||
* 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);
|
||||
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
|
||||
dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->buffer);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
@ -4220,8 +4579,8 @@ comm_point_send_reply(struct comm_reply *repinfo)
|
||||
*/
|
||||
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,
|
||||
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
|
||||
dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->client_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
|
||||
|
@ -128,10 +128,11 @@ struct comm_reply {
|
||||
/** the comm_point with fd to send reply on to. */
|
||||
struct comm_point* c;
|
||||
/** the address (for UDP based communication) */
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr_storage remote_addr;
|
||||
/** length of address */
|
||||
socklen_t addrlen;
|
||||
/** return type 0 (none), 4(IP4), 6(IP6) */
|
||||
socklen_t remote_addrlen;
|
||||
/** return type 0 (none), 4(IP4), 6(IP6)
|
||||
* used only with listen_type_udp_ancil* */
|
||||
int srctype;
|
||||
/* DnsCrypt context */
|
||||
#ifdef USE_DNSCRYPT
|
||||
@ -155,6 +156,13 @@ struct comm_reply {
|
||||
pktinfo;
|
||||
/** max udp size for udp packets */
|
||||
size_t max_udp_size;
|
||||
/* if set, the request came through a proxy */
|
||||
int is_proxied;
|
||||
/** the client address
|
||||
* the same as remote_addr if not proxied */
|
||||
struct sockaddr_storage client_addr;
|
||||
/** the original address length */
|
||||
socklen_t client_addrlen;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -278,6 +286,19 @@ struct comm_point {
|
||||
/** variable with type of socket, UDP,TCP-accept,TCP,pipe */
|
||||
type;
|
||||
|
||||
/* -------- PROXYv2 ------- */
|
||||
/** if set, PROXYv2 is expected on this connection */
|
||||
int pp2_enabled;
|
||||
/** header state for the PROXYv2 header (for TCP) */
|
||||
enum {
|
||||
/** no header encounter yet */
|
||||
pp2_header_none = 0,
|
||||
/** read the static part of the header */
|
||||
pp2_header_init,
|
||||
/** read the full header */
|
||||
pp2_header_done
|
||||
} pp2_header_state;
|
||||
|
||||
/* ---------- Behaviour ----------- */
|
||||
/** if set the connection is NOT closed on delete. */
|
||||
int do_not_close;
|
||||
@ -498,6 +519,7 @@ struct ub_event_base* comm_base_internal(struct comm_base* b);
|
||||
* @param base: in which base to alloc the commpoint.
|
||||
* @param fd: file descriptor of open UDP socket.
|
||||
* @param buffer: shared buffer by UDP sockets from this thread.
|
||||
* @param pp2_enabled: if the comm point will support PROXYv2.
|
||||
* @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.
|
||||
@ -505,7 +527,7 @@ struct ub_event_base* comm_base_internal(struct comm_base* b);
|
||||
* 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,
|
||||
int fd, struct sldns_buffer* buffer, int pp2_enabled,
|
||||
comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket);
|
||||
|
||||
/**
|
||||
@ -515,6 +537,7 @@ struct comm_point* comm_point_create_udp(struct comm_base* base,
|
||||
* @param base: in which base to alloc the commpoint.
|
||||
* @param fd: file descriptor of open UDP socket.
|
||||
* @param buffer: shared buffer by UDP sockets from this thread.
|
||||
* @param pp2_enabled: if the comm point will support PROXYv2.
|
||||
* @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.
|
||||
@ -522,7 +545,7 @@ struct comm_point* comm_point_create_udp(struct comm_base* base,
|
||||
* 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,
|
||||
int fd, struct sldns_buffer* buffer, int pp2_enabled,
|
||||
comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket);
|
||||
|
||||
/**
|
||||
@ -544,6 +567,7 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base,
|
||||
* or NULL to not create those structures in the tcp handlers.
|
||||
* @param port_type: the type of port we are creating a TCP listener for. Used
|
||||
* to select handler type to use.
|
||||
* @param pp2_enabled: if the comm point will support PROXYv2.
|
||||
* @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.
|
||||
@ -557,7 +581,7 @@ struct comm_point* comm_point_create_tcp(struct comm_base* base,
|
||||
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,
|
||||
enum listen_type port_type, int pp2_enabled,
|
||||
comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket);
|
||||
|
||||
/**
|
||||
|
139
util/proxy_protocol.c
Normal file
139
util/proxy_protocol.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* util/proxy_protocol.c - event notification
|
||||
*
|
||||
* Copyright (c) 2022, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains PROXY protocol functions.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "util/log.h"
|
||||
#include "util/proxy_protocol.h"
|
||||
|
||||
int
|
||||
pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src,
|
||||
int stream)
|
||||
{
|
||||
int af;
|
||||
if(!src) return 0;
|
||||
af = (int)((struct sockaddr_in*)src)->sin_family;
|
||||
if(sldns_buffer_remaining(buf) <
|
||||
PP2_HEADER_SIZE + (af==AF_INET?12:36)) {
|
||||
return 0;
|
||||
}
|
||||
/* sig */
|
||||
sldns_buffer_write(buf, PP2_SIG, PP2_SIG_LEN);
|
||||
/* version and command */
|
||||
sldns_buffer_write_u8(buf, (PP2_VERSION << 4) | PP2_CMD_PROXY);
|
||||
if(af==AF_INET) {
|
||||
/* family and protocol */
|
||||
sldns_buffer_write_u8(buf,
|
||||
(PP2_AF_INET<<4) |
|
||||
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM));
|
||||
/* length */
|
||||
sldns_buffer_write_u16(buf, 12);
|
||||
/* src addr */
|
||||
sldns_buffer_write(buf,
|
||||
&((struct sockaddr_in*)src)->sin_addr.s_addr, 4);
|
||||
/* dst addr */
|
||||
sldns_buffer_write_u32(buf, 0);
|
||||
/* src port */
|
||||
sldns_buffer_write(buf,
|
||||
&((struct sockaddr_in*)src)->sin_port, 2);
|
||||
/* dst port */
|
||||
sldns_buffer_write_u16(buf, 0);
|
||||
} else {
|
||||
/* family and protocol */
|
||||
sldns_buffer_write_u8(buf,
|
||||
(PP2_AF_INET6<<4) |
|
||||
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM));
|
||||
/* length */
|
||||
sldns_buffer_write_u16(buf, 36);
|
||||
/* src addr */
|
||||
sldns_buffer_write(buf,
|
||||
&((struct sockaddr_in6*)src)->sin6_addr, 16);
|
||||
/* dst addr */
|
||||
sldns_buffer_set_at(buf,
|
||||
sldns_buffer_position(buf), 0, 16);
|
||||
sldns_buffer_skip(buf, 16);
|
||||
/* src port */
|
||||
sldns_buffer_write(buf,
|
||||
&((struct sockaddr_in6*)src)->sin6_port, 2);
|
||||
/* dst port */
|
||||
sldns_buffer_write_u16(buf, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct pp2_header*
|
||||
pp2_read_header(struct sldns_buffer* buf)
|
||||
{
|
||||
size_t size;
|
||||
struct pp2_header* header = (struct pp2_header*)sldns_buffer_begin(buf);
|
||||
/* Try to fail all the unsupported cases first. */
|
||||
if(sldns_buffer_remaining(buf) < PP2_HEADER_SIZE) {
|
||||
log_err("proxy_protocol: not enough space for header");
|
||||
return NULL;
|
||||
}
|
||||
/* Check for PROXYv2 header */
|
||||
if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 ||
|
||||
((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) {
|
||||
log_err("proxy_protocol: could not match PROXYv2 header");
|
||||
return NULL;
|
||||
}
|
||||
/* Check the length */
|
||||
size = PP2_HEADER_SIZE + ntohs(header->len);
|
||||
if(sldns_buffer_remaining(buf) < size) {
|
||||
log_err("proxy_protocol: not enough space for header");
|
||||
return NULL;
|
||||
}
|
||||
/* Check for supported commands */
|
||||
if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL &&
|
||||
(header->ver_cmd & 0xF) != PP2_CMD_PROXY) {
|
||||
log_err("proxy_protocol: unsupported command");
|
||||
return NULL;
|
||||
}
|
||||
/* Check for supported family and protocol */
|
||||
if(header->fam_prot != 0x00 /* AF_UNSPEC|UNSPEC */ &&
|
||||
header->fam_prot != 0x11 /* AF_INET|STREAM */ &&
|
||||
header->fam_prot != 0x12 /* AF_INET|DGRAM */ &&
|
||||
header->fam_prot != 0x21 /* AF_INET6|STREAM */ &&
|
||||
header->fam_prot != 0x22 /* AF_INET6|DGRAM */) {
|
||||
log_err("proxy_protocol: unsupported family and protocol");
|
||||
return NULL;
|
||||
}
|
||||
/* We have a correct header */
|
||||
return header;
|
||||
}
|
131
util/proxy_protocol.h
Normal file
131
util/proxy_protocol.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* util/proxy_protocol.h - PROXY protocol
|
||||
*
|
||||
* Copyright (c) 2022, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains PROXY protocol structs and functions.
|
||||
* Only v2 is supported. TLVs are not currently supported.
|
||||
*/
|
||||
#ifndef PROXY_PROTOCOL_H
|
||||
#define PROXY_PROTOCOL_H
|
||||
|
||||
#include "sldns/sbuffer.h"
|
||||
|
||||
/** PROXYv2 minimum header size */
|
||||
#define PP2_HEADER_SIZE 16
|
||||
|
||||
/** PROXYv2 header signature */
|
||||
#define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
|
||||
#define PP2_SIG_LEN 12
|
||||
|
||||
/** PROXYv2 version */
|
||||
#define PP2_VERSION 0x2
|
||||
|
||||
/**
|
||||
* PROXYv2 command.
|
||||
*/
|
||||
enum pp2_command {
|
||||
PP2_CMD_LOCAL = 0x0,
|
||||
PP2_CMD_PROXY = 0x1
|
||||
};
|
||||
|
||||
/**
|
||||
* PROXYv2 address family.
|
||||
*/
|
||||
enum pp2_af {
|
||||
PP2_AF_UNSPEC = 0x0,
|
||||
PP2_AF_INET = 0x1,
|
||||
PP2_AF_INET6 = 0x2,
|
||||
PP2_AF_UNIX = 0x3
|
||||
};
|
||||
|
||||
/**
|
||||
* PROXYv2 protocol.
|
||||
*/
|
||||
enum pp2_protocol {
|
||||
PP2_PROT_UNSPEC = 0x0,
|
||||
PP2_PROT_STREAM = 0x1,
|
||||
PP2_PROT_DGRAM = 0x2
|
||||
};
|
||||
|
||||
/**
|
||||
* PROXYv2 header.
|
||||
*/
|
||||
struct pp2_header {
|
||||
uint8_t sig[PP2_SIG_LEN];
|
||||
uint8_t ver_cmd;
|
||||
uint8_t fam_prot;
|
||||
uint16_t len;
|
||||
union {
|
||||
struct { /* for TCP/UDP over IPv4, len = 12 */
|
||||
uint32_t src_addr;
|
||||
uint32_t dst_addr;
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
} addr4;
|
||||
struct { /* for TCP/UDP over IPv6, len = 36 */
|
||||
uint8_t src_addr[16];
|
||||
uint8_t dst_addr[16];
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
} addr6;
|
||||
struct { /* for AF_UNIX sockets, len = 216 */
|
||||
uint8_t src_addr[108];
|
||||
uint8_t dst_addr[108];
|
||||
} addru;
|
||||
} addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write a PROXYv2 header at the current position of the buffer.
|
||||
* @param buf: the buffer to write to.
|
||||
* @param src: the source address.
|
||||
* @param stream: if the protocol is stream or datagram.
|
||||
* @return 1 on success, 0 on failure.
|
||||
*/
|
||||
int pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src,
|
||||
int stream);
|
||||
|
||||
/**
|
||||
* Read a PROXYv2 header from the current position of the buffer.
|
||||
* It does initial validation and returns a pointer to the buffer position on
|
||||
* success.
|
||||
* @param buf: the buffer to read from.
|
||||
* @return the pointer to the buffer position on success, NULL on error.
|
||||
*/
|
||||
struct pp2_header* pp2_read_header(struct sldns_buffer* buf);
|
||||
|
||||
#endif /* PROXY_PROTOCOL_H */
|
Loading…
Reference in New Issue
Block a user