|
version 1.1.1.2, 2021/03/17 00:56:46
|
version 1.1.1.3, 2023/09/27 11:02:07
|
|
Line 1
|
Line 1
|
| /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
| |
|
| This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
|
Line 178 size_t add_pseudoheader(struct dns_header *header, siz
|
Line 178 size_t add_pseudoheader(struct dns_header *header, siz
|
| memcpy(buff, datap, rdlen); |
memcpy(buff, datap, rdlen); |
| |
|
| /* now, delete OPT RR */ |
/* now, delete OPT RR */ |
| plen = rrfilter(header, plen, 0); | plen = rrfilter(header, plen, RRFILTER_EDNS0); |
| |
|
| /* Now, force addition of a new one */ |
/* Now, force addition of a new one */ |
| p = NULL; |
p = NULL; |
|
Line 264 static void encoder(unsigned char *in, char *out)
|
Line 264 static void encoder(unsigned char *in, char *out)
|
| out[3] = char64(in[2]); |
out[3] = char64(in[2]); |
| } |
} |
| |
|
| |
/* OPT_ADD_MAC = MAC is added (if available) |
| |
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed |
| |
OPT_STRIP_MAC = MAC is removed */ |
| static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, |
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, |
| union mysockaddr *l3, time_t now, int *cacheablep) |
union mysockaddr *l3, time_t now, int *cacheablep) |
| { |
{ |
| int maclen, replace = 2; /* can't get mac address, just delete any incoming. */ | int replace = 0, maclen = 0; |
| unsigned char mac[DHCP_CHADDR_MAX]; |
unsigned char mac[DHCP_CHADDR_MAX]; |
| char encode[18]; /* handle 6 byte MACs */ | char encode[18]; /* handle 6 byte MACs ONLY */ |
| |
|
| if ((maclen = find_mac(l3, mac, 1, now)) == 6) | if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6) |
| { |
{ |
| replace = 1; | if (option_bool(OPT_STRIP_MAC)) |
| *cacheablep = 0; | replace = 1; |
| *cacheablep = 0; |
| if (option_bool(OPT_MAC_HEX)) | |
| print_mac(encode, mac, maclen); | if (option_bool(OPT_MAC_HEX)) |
| else | print_mac(encode, mac, maclen); |
| { | else |
| encoder(mac, encode); | { |
| encoder(mac+3, encode+4); | encoder(mac, encode); |
| encode[8] = 0; | encoder(mac+3, encode+4); |
| } | encode[8] = 0; |
| | } |
| } |
} |
| |
else if (option_bool(OPT_STRIP_MAC)) |
| |
replace = 2; |
| |
|
| return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace); | if (replace != 0 || maclen == 6) |
| | plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace); |
| | |
| | return plen; |
| } |
} |
| |
|
| |
|
| |
/* OPT_ADD_MAC = MAC is added (if available) |
| |
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed |
| |
OPT_STRIP_MAC = MAC is removed */ |
| static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, |
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, |
| union mysockaddr *l3, time_t now, int *cacheablep) |
union mysockaddr *l3, time_t now, int *cacheablep) |
| { |
{ |
| int maclen; | int maclen = 0, replace = 0; |
| unsigned char mac[DHCP_CHADDR_MAX]; |
unsigned char mac[DHCP_CHADDR_MAX]; |
| |
| if ((maclen = find_mac(l3, mac, 1, now)) != 0) | if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0) |
| { |
{ |
| *cacheablep = 0; |
*cacheablep = 0; |
| plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0); | if (option_bool(OPT_STRIP_MAC)) |
| | replace = 1; |
| } |
} |
| |
else if (option_bool(OPT_STRIP_MAC)) |
| |
replace = 2; |
| |
|
| |
if (replace != 0 || maclen != 0) |
| |
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace); |
| |
|
| return plen; |
return plen; |
| } |
} |
| |
|
|
Line 378 static size_t calc_subnet_opt(struct subnet_opt *opt,
|
Line 396 static size_t calc_subnet_opt(struct subnet_opt *opt,
|
| return len + 4; |
return len + 4; |
| } |
} |
| |
|
| static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable) | /* OPT_CLIENT_SUBNET = client subnet is added |
| | OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced |
| | OPT_STRIP_ECS = client subnet is removed */ |
| | static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, |
| | union mysockaddr *source, int *cacheable) |
| { |
{ |
| /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ |
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ |
| |
|
| int len; | int replace = 0, len = 0; |
| struct subnet_opt opt; |
struct subnet_opt opt; |
| |
|
| len = calc_subnet_opt(&opt, source, cacheable); | if (option_bool(OPT_CLIENT_SUBNET)) |
| return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0); | { |
| | if (option_bool(OPT_STRIP_ECS)) |
| | replace = 1; |
| | len = calc_subnet_opt(&opt, source, cacheable); |
| | } |
| | else if (option_bool(OPT_STRIP_ECS)) |
| | replace = 2; |
| | else |
| | return plen; |
| | |
| | return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace); |
| } |
} |
| |
|
| int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer) |
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer) |
|
Line 427 int check_source(struct dns_header *header, size_t ple
|
Line 459 int check_source(struct dns_header *header, size_t ple
|
| return 1; |
return 1; |
| } |
} |
| |
|
| |
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for |
| |
* detailed information on packet formating. |
| |
*/ |
| |
#define UMBRELLA_VERSION 1 |
| |
#define UMBRELLA_TYPESZ 2 |
| |
|
| |
#define UMBRELLA_ASSET 0x0004 |
| |
#define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset) |
| |
#define UMBRELLA_ORG 0x0008 |
| |
#define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org) |
| |
#define UMBRELLA_IPV4 0x0010 |
| |
#define UMBRELLA_IPV6 0x0020 |
| |
#define UMBRELLA_DEVICE 0x0040 |
| |
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device) |
| |
|
| |
struct umbrella_opt { |
| |
u8 magic[4]; |
| |
u8 version; |
| |
u8 flags; |
| |
/* We have 4 possible fields since we'll never send both IPv4 and |
| |
* IPv6, so using the larger of the two to calculate max buffer size. |
| |
* Each field also has a type header. So the following accounts for |
| |
* the type headers and each field size to get a max buffer size. |
| |
*/ |
| |
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ]; |
| |
}; |
| |
|
| |
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable) |
| |
{ |
| |
*cacheable = 0; |
| |
|
| |
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}}; |
| |
u8 *u = &opt.fields[0]; |
| |
int family = source->sa.sa_family; |
| |
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ; |
| |
|
| |
if (daemon->umbrella_org) |
| |
{ |
| |
PUTSHORT(UMBRELLA_ORG, u); |
| |
PUTLONG(daemon->umbrella_org, u); |
| |
} |
| |
|
| |
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u); |
| |
memcpy(u, get_addrp(source, family), size); |
| |
u += size; |
| |
|
| |
if (option_bool(OPT_UMBRELLA_DEVID)) |
| |
{ |
| |
PUTSHORT(UMBRELLA_DEVICE, u); |
| |
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ); |
| |
u += UMBRELLA_DEVICESZ; |
| |
} |
| |
|
| |
if (daemon->umbrella_asset) |
| |
{ |
| |
PUTSHORT(UMBRELLA_ASSET, u); |
| |
PUTLONG(daemon->umbrella_asset, u); |
| |
} |
| |
|
| |
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1); |
| |
} |
| |
|
| /* Set *check_subnet if we add a client subnet option, which needs to checked |
/* Set *check_subnet if we add a client subnet option, which needs to checked |
| in the reply. Set *cacheable to zero if we add an option which the answer |
in the reply. Set *cacheable to zero if we add an option which the answer |
| may depend on. */ |
may depend on. */ |
| size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, |
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, |
| union mysockaddr *source, time_t now, int *check_subnet, int *cacheable) | union mysockaddr *source, time_t now, int *cacheable) |
| { |
{ |
| *check_subnet = 0; |
|
| *cacheable = 1; |
*cacheable = 1; |
| |
|
| if (option_bool(OPT_ADD_MAC)) | plen = add_mac(header, plen, limit, source, now, cacheable); |
| plen = add_mac(header, plen, limit, source, now, cacheable); | plen = add_dns_client(header, plen, limit, source, now, cacheable); |
| |
|
| if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) |
|
| plen = add_dns_client(header, plen, limit, source, now, cacheable); |
|
| |
|
| if (daemon->dns_client_id) |
if (daemon->dns_client_id) |
| plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, |
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, |
| (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1); |
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1); |
| |
|
| |
if (option_bool(OPT_UMBRELLA)) |
| |
plen = add_umbrella_opt(header, plen, limit, source, cacheable); |
| |
|
| if (option_bool(OPT_CLIENT_SUBNET)) | plen = add_source_addr(header, plen, limit, source, cacheable); |
| { | |
| plen = add_source_addr(header, plen, limit, source, cacheable); | |
| *check_subnet = 1; | |
| } | |
| | |
| return plen; |
return plen; |
| } |
} |