mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Add support for arbitrary prefix lengths in --rev-server and --domain=....,local
Previously, the prefix was limited to [8,16,24,32] for IPv4 and to multiples of 4 for IPv6. This patch also makes the prefix-length optional for --rev-server. Inspired by a patch from DL6ER <dl6er@dl6er.de>, but completely re-written by srk. All bugs are his.
This commit is contained in:
@@ -1586,6 +1586,9 @@ void check_servers(int no_loop_check)
|
||||
if (serv->sfd)
|
||||
serv->sfd->used = 1;
|
||||
|
||||
if (count == SERVERS_LOGGED)
|
||||
my_syslog(LOG_INFO, _("more servers are defined but not logged"));
|
||||
|
||||
if (++count > SERVERS_LOGGED)
|
||||
continue;
|
||||
|
||||
|
||||
205
src/option.c
205
src/option.c
@@ -935,52 +935,132 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int domain_rev4(char *domain, struct in_addr addr, int msize)
|
||||
static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int size)
|
||||
{
|
||||
in_addr_t a = ntohl(addr.s_addr);
|
||||
|
||||
*domain = 0;
|
||||
int i, j;
|
||||
char *string;
|
||||
int msize;
|
||||
u16 flags = 0;
|
||||
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
switch (msize)
|
||||
{
|
||||
case 32:
|
||||
domain += sprintf(domain, "%u.", a & 0xff);
|
||||
/* fall through */
|
||||
case 24:
|
||||
domain += sprintf(domain, "%d.", (a >> 8) & 0xff);
|
||||
/* fall through */
|
||||
case 16:
|
||||
domain += sprintf(domain, "%d.", (a >> 16) & 0xff);
|
||||
/* fall through */
|
||||
case 8:
|
||||
domain += sprintf(domain, "%d.", (a >> 24) & 0xff);
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
rem = size & 0x7;
|
||||
addrbytes = (32 - size) >> 3;
|
||||
addrbits = (32 - size) & 7;
|
||||
|
||||
if (size > 32 | size < 1)
|
||||
return _("bad IPv4 prefix length");
|
||||
|
||||
for (i = 0; i < addrbytes; i++)
|
||||
if (((u8 *)addr4)[3-i] != 0)
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
if (i != addrbytes || (((u8 *)addr4)[3-addrbytes] & ((1 << addrbits) - 1)) != 0)
|
||||
return _("address part not zero");
|
||||
|
||||
size = size & ~0x7;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (8 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/8;
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr4)[j];
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
string += sprintf(string, "%d.", dig);
|
||||
}
|
||||
|
||||
sprintf(string, "in-addr.arpa");
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
|
||||
sprintf(domain, "in-addr.arpa");
|
||||
|
||||
return 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int domain_rev6(char *domain, struct in6_addr *addr, int msize)
|
||||
static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, int size)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
char *string;
|
||||
int msize;
|
||||
u16 flags = 0;
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
if (msize > 128 || msize%4)
|
||||
return 0;
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
*domain = 0;
|
||||
rem = size & 0x3;
|
||||
addrbytes = (128 - size) >> 3;
|
||||
addrbits = (128 - size) & 7;
|
||||
|
||||
if (size > 128 || size < 1)
|
||||
return _("bad IPv6 prefix length");
|
||||
|
||||
for (i = msize-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)addr)[i>>3];
|
||||
domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
for (i = 0; i < addrbytes; i++)
|
||||
if (addr6->s6_addr[15-i] != 0)
|
||||
break;
|
||||
|
||||
if (i != addrbytes || (addr6->s6_addr[15-addrbytes] & ((1 << addrbits) - 1)) != 0)
|
||||
return _("address part not zero");
|
||||
|
||||
size = size & ~0x3;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (4 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/4;
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr6)[j>>1];
|
||||
|
||||
dig = j & 1 ? dig & 15 : dig >> 4;
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
string += sprintf(string, "%.1x.", dig);
|
||||
}
|
||||
|
||||
sprintf(string, "ip6.arpa");
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
sprintf(domain, "ip6.arpa");
|
||||
|
||||
return 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -2308,17 +2388,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
|
||||
ret_err_free(_("bad prefix"), new);
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
else if (strcmp(arg, "local") != 0)
|
||||
ret_err_free(gen_err, new);
|
||||
else
|
||||
{
|
||||
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
|
||||
/* local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
/* domain_rev4 can't fail here, msize checked above. */
|
||||
domain_rev4(domain, new->start, msize);
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
|
||||
|
||||
domain_rev4(0, NULL, &new->start, msize);
|
||||
|
||||
/* local=/<domain>/ */
|
||||
/* d_raw can't failed to canonicalise here, checked above. */
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
|
||||
@@ -2353,16 +2429,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
|
||||
ret_err_free(_("bad prefix"), new);
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
else if (strcmp(arg, "local") != 0)
|
||||
ret_err_free(gen_err, new);
|
||||
else
|
||||
{
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
/* generate the equivalent of
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
domain_rev6(domain, &new->start6, msize);
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
|
||||
|
||||
domain_rev6(0, NULL, &new->start6, msize);
|
||||
|
||||
/* local=/<domain>/ */
|
||||
/* d_raw can't failed to canonicalise here, checked above. */
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
|
||||
@@ -2735,46 +2809,37 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
char *string;
|
||||
int size;
|
||||
u16 flags = 0;
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
|
||||
unhide_metas(arg);
|
||||
if (!arg)
|
||||
ret_err(gen_err);
|
||||
|
||||
comma=split(arg);
|
||||
|
||||
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
size = -1;
|
||||
|
||||
if (inet_pton(AF_INET, arg, &addr4))
|
||||
{
|
||||
if (!domain_rev4(domain, addr4, size))
|
||||
ret_err(_("bad IPv4 prefix"));
|
||||
if (size == -1)
|
||||
size = 32;
|
||||
|
||||
if ((string = domain_rev4(servers_only, comma, &addr4, size)))
|
||||
ret_err(string);
|
||||
}
|
||||
else if (inet_pton(AF_INET6, arg, &addr6))
|
||||
{
|
||||
if (!domain_rev6(domain, &addr6, size))
|
||||
ret_err(_("bad IPv6 prefix"));
|
||||
if (size == -1)
|
||||
size = 128;
|
||||
|
||||
if ((string = domain_rev6(servers_only, comma, &addr6, size)))
|
||||
ret_err(string);
|
||||
}
|
||||
else
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!comma)
|
||||
flags |= SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(comma, &serv_addr, &source_addr, interface, &flags)))
|
||||
ret_err(string);
|
||||
|
||||
if (servers_only)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
ret_err(gen_err);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user