diff --git a/src/dns.c b/src/dns.c index 4fe2c59..da37327 100644 --- a/src/dns.c +++ b/src/dns.c @@ -871,15 +871,16 @@ int dns_add_OPT_ECS(struct dns_packet *packet, struct dns_opt_ecs *ecs) struct dns_opt *opt = (struct dns_opt *)opt_data; int len = 0; - opt->code = DNS_OPT_T_ECS; - opt->length = sizeof(*ecs); - memcpy(opt->data, ecs, sizeof(*ecs)); - /* ecs size 4 + bit of address*/ - len = sizeof(*opt) + 4; + len = 4; len += (ecs->source_prefix / 8); len += (ecs->source_prefix % 8 > 0) ? 1 : 0; + opt->length = len; + opt->code = DNS_OPT_T_ECS; + memcpy(opt->data, ecs, len); + len += sizeof(*opt); + return _dns_add_RAW(packet, DNS_RRS_OPT, DNS_OPT_T_ECS, "", 0, opt_data, len); } @@ -1468,9 +1469,20 @@ static int _dns_encode_OPT(struct dns_context *context, struct dns_rrs *rrs) return -1; } - memcpy(context->ptr, dns_opt->data, dns_opt->length); - context->ptr += dns_opt->length; - + switch (dns_opt->code) { + case DNS_OPT_T_ECS: { + struct dns_opt_ecs *ecs = (struct dns_opt_ecs *)&(dns_opt->data); + _dns_write_short(&context->ptr, ecs->family); + _dns_write_char(&context->ptr, ecs->source_prefix); + _dns_write_char(&context->ptr, ecs->scope_prefix); + memcpy(context->ptr, ecs->addr, dns_opt->length - 4); + context->ptr += dns_opt->length - 4; + } break; + default: + memcpy(context->ptr, dns_opt->data, dns_opt->length); + context->ptr += dns_opt->length; + break; + } return 0; } @@ -1756,21 +1768,21 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type) return -1; } } break; - // case DNS_T_OPT: { - // unsigned char *opt_start = context->ptr; - // ret = _dns_decode_opt(context, type, ttl, rr_len); - // if (ret < 0) { - // tlog(TLOG_ERROR, "decode opt failed, %s", domain); - // return -1; - // } + case DNS_T_OPT: { + unsigned char *opt_start = context->ptr; + ret = _dns_decode_opt(context, type, ttl, rr_len); + if (ret < 0) { + tlog(TLOG_ERROR, "decode opt failed, %s", domain); + return -1; + } - // if (context->ptr - opt_start != rr_len) { - // tlog(TLOG_ERROR, "opt length mismatch, %s\n", domain); - // return -1; - // } + if (context->ptr - opt_start != rr_len) { + tlog(TLOG_ERROR, "opt length mismatch, %s\n", domain); + return -1; + } - // dns_set_OPT_payload_size(packet, qclass); - // } break; + dns_set_OPT_payload_size(packet, qclass); + } break; default: { unsigned char raw_data[1024]; if (_dns_left_len(context) < rr_len || rr_len >= sizeof(raw_data)) { diff --git a/src/dns.h b/src/dns.h index 66ab48c..2802902 100644 --- a/src/dns.h +++ b/src/dns.h @@ -177,7 +177,7 @@ struct dns_opt_ecs { unsigned char source_prefix; unsigned char scope_prefix; unsigned char addr[DNS_RR_AAAA_LEN]; -}; +} __attribute__((packed));; /* OPT COOLIE */ struct dns_opt_cookie { diff --git a/src/dns_client.c b/src/dns_client.c index 77b2212..912c9ad 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -3273,6 +3273,34 @@ static void *_dns_client_work(void *arg) int dns_client_set_ecs(char *ip, int subnet) { + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len); + + switch (addr.ss_family) { + case AF_INET: { + struct sockaddr_in *addr_in; + addr_in = (struct sockaddr_in *)&addr; + memcpy(&client.ecs_ipv4.ipv4_addr, &addr_in->sin_addr.s_addr, 4); + client.ecs_ipv4.bitlen = subnet; + client.ecs_ipv4.enable = 1; + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6; + addr_in6 = (struct sockaddr_in6 *)&addr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { + memcpy(&client.ecs_ipv4.ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4); + client.ecs_ipv4.bitlen = subnet; + client.ecs_ipv4.enable = 1; + } else { + memcpy(&client.ecs_ipv6.ipv6_addr, addr_in6->sin6_addr.s6_addr, 16); + client.ecs_ipv6.bitlen = subnet; + client.ecs_ipv6.enable = 1; + } + } break; + default: + return -1; + } return 0; } diff --git a/src/dns_conf.c b/src/dns_conf.c index 40fdafc..d583e1f 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -1257,7 +1257,7 @@ static int _conf_edns_client_subnet(void *data, int argc, char *argv[]) struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); - if (argc <= 1 || data == NULL) { + if (argc <= 1) { return -1; }