miniupnpd: Add validation that public ip address is not reserved and is really public

This ensures that all requests for getting public IP address (either via UPnP IGD or PCP/PMP) would contain correct public IP address or an error (instead of some invalid private/reserved IP address).
This commit is contained in:
Pali Rohár 2018-05-19 13:31:26 +02:00
parent c35935c61d
commit cce19781e6
4 changed files with 29 additions and 3 deletions

View File

@ -990,6 +990,12 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) { if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {
/* error */ /* error */
fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str); fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);
return -1;
}
if(addr_is_reserved(&lan_addr->ext_ip_addr)) {
/* error */
fprintf(stderr, "Error: option ext_ip address contains reserved / private address : %s\n", lan_addr->ext_ip_str);
return -1;
} }
} }
} }
@ -1070,6 +1076,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
int pid; int pid;
int debug_flag = 0; int debug_flag = 0;
int openlog_option; int openlog_option;
struct in_addr addr;
struct sigaction sa; struct sigaction sa;
/*const char * logfilename = 0;*/ /*const char * logfilename = 0;*/
const char * presurl = 0; const char * presurl = 0;
@ -1606,6 +1613,17 @@ init(int argc, char * * argv, struct runtime_vars * v)
goto print_usage; goto print_usage;
} }
if (use_ext_ip_addr) {
if (inet_pton(AF_INET, use_ext_ip_addr, &addr) != 1) {
fprintf(stderr, "Error: option ext_ip contains invalid address %s\n", use_ext_ip_addr);
return 1;
}
if (addr_is_reserved(&addr)) {
fprintf(stderr, "Error: option ext_ip contains reserved / private address %s, not public routable\n", use_ext_ip_addr);
return 1;
}
}
if(debug_flag) if(debug_flag)
{ {
pid = getpid(); pid = getpid();

View File

@ -94,6 +94,7 @@ error:
static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr) static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr)
{ {
#ifndef MULTIPLE_EXTERNAL_IP #ifndef MULTIPLE_EXTERNAL_IP
struct in_addr addr;
char tmp[16]; char tmp[16];
UNUSED(senderaddr); UNUSED(senderaddr);
@ -103,10 +104,13 @@ static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr
if(!ext_if_name || ext_if_name[0]=='\0') { if(!ext_if_name || ext_if_name[0]=='\0') {
resp[3] = 3; /* Network Failure (e.g. NAT box itself resp[3] = 3; /* Network Failure (e.g. NAT box itself
* has not obtained a DHCP lease) */ * has not obtained a DHCP lease) */
} else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN, NULL, NULL) < 0) { } else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN, &addr, NULL) < 0) {
syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name); syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name);
resp[3] = 3; /* Network Failure (e.g. NAT box itself resp[3] = 3; /* Network Failure (e.g. NAT box itself
* has not obtained a DHCP lease) */ * has not obtained a DHCP lease) */
} else if (addr_is_reserved(&addr)) {
resp[3] = 3; /* Network Failure, box has not obtained
public IP address */
} else { } else {
inet_pton(AF_INET, tmp, resp+8); /* ok */ inet_pton(AF_INET, tmp, resp+8); /* ok */
} }

View File

@ -1281,8 +1281,9 @@ genEventVars(int * len, const struct serviceDesc * s)
if(use_ext_ip_addr) if(use_ext_ip_addr)
str = strcat_str(str, len, &tmplen, use_ext_ip_addr); str = strcat_str(str, len, &tmplen, use_ext_ip_addr);
else { else {
struct in_addr addr;
char ext_ip_addr[INET_ADDRSTRLEN]; char ext_ip_addr[INET_ADDRSTRLEN];
if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) { if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, &addr, NULL) < 0 || addr_is_reserved(&addr)) {
str = strcat_str(str, len, &tmplen, "0.0.0.0"); str = strcat_str(str, len, &tmplen, "0.0.0.0");
} else { } else {
str = strcat_str(str, len, &tmplen, ext_ip_addr); str = strcat_str(str, len, &tmplen, ext_ip_addr);

View File

@ -332,17 +332,20 @@ GetExternalIPAddress(struct upnphttp * h, const char * action, const char * ns)
* There is usually no NAT with IPv6 */ * There is usually no NAT with IPv6 */
#ifndef MULTIPLE_EXTERNAL_IP #ifndef MULTIPLE_EXTERNAL_IP
struct in_addr addr;
if(use_ext_ip_addr) if(use_ext_ip_addr)
{ {
strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN); strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
ext_ip_addr[INET_ADDRSTRLEN - 1] = '\0'; ext_ip_addr[INET_ADDRSTRLEN - 1] = '\0';
} }
else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, &addr, NULL) < 0)
{ {
syslog(LOG_ERR, "Failed to get ip address for interface %s", syslog(LOG_ERR, "Failed to get ip address for interface %s",
ext_if_name); ext_if_name);
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
} }
if (addr_is_reserved(&addr))
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
#else #else
struct lan_addr_s * lan_addr; struct lan_addr_s * lan_addr;
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);