diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index c93651d..d03ef2d 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -49,6 +49,7 @@ #include #include +const char *conffile = "/etc/dns_port.conf"; typedef ISC_LIST(dns_dispentry_t) dns_displist_t; typedef struct dispsocket dispsocket_t; @@ -1933,6 +1934,168 @@ open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, return (ISC_R_SUCCESS); } +static int convert_num(char *str) +{ + int negative = 0; + int tval; + int val = 0; + int base = 10; + char *ptr = str; + if (str == NULL) + return -ISC_R_FAILURE; + + if (*ptr == '-') { + negative = 1; + ++ptr; + } + + do { + tval = *ptr++; + /* XXX assumes ASCII... */ + if (tval >= '0') + tval -= '0'; + else { + syslog (LOG_ERR, "Bogus number: %s.", str); + return -ISC_R_BADNUMBER; + } + if (tval >= base) { + syslog (LOG_ERR, "Bogus number: %s.", str); + return -ISC_R_BADNUMBER; + } + val = val * base + tval; + } while (*ptr); + + if (negative) + val = -val; + return val; +} + +static int str_token(char *str, int *digit, unsigned int len, const char *semi) +{ + int num = 0; + char *p; + p = strtok(str, semi); + while (p !=NULL) { + if (num >= len-1) { + digit[num] = '\0'; + break; + } + /* convert string to integer */ + digit[num] = convert_num(p); + if (digit[num] < 0) + return -ISC_R_BADNUMBER; + + p = strtok(NULL, semi); + num++; + } + + return num; +} + +static int parse_port_config(const char *buffer, const char *sub_buf, int *ports, unsigned int len, const char *semi) +{ + char *str; + char string[256] = {0}; + int start, end; + int ret = -ISC_R_DISABLED; + + if (str = strstr(buffer, sub_buf)) { + start = strlen(sub_buf); + end = strlen(str); + strncpy(string, str + start, end - start -1); + /* string segmentation with semi character */ + ret = str_token(string, ports, len, semi); + if (ret < 0) + return -ISC_R_BADNUMBER; + } + + return ret; +} + +static isc_result_t +parse_config(const char *file, in_port_t *port_lo, in_port_t *port_hi, in_port_t *no_use_ports) +{ + FILE *fp; + char *str = NULL; + char buffer[256] = {0}; + int ports[8] = {0}; + int unports[17] = {0}; + int i = 0; + int ret; + + fp = fopen(file, "r"); + if (fp) { + while (fgets(buffer, 256, fp)) { + const char *buffer_s = buffer; + str = buffer; + /* skip the comment line */ + while (isspace(*str)) + str++; + if (strncmp(str, "#", 1) == 0) + continue; + /* get default set of dispatch ports */ + ret = parse_port_config(buffer_s, "dns-range-port", ports, 8, " "); + if (ret == 2) { + *port_lo = (in_port_t)ports[0]; + *port_hi = (in_port_t)ports[1]; + if (*port_lo < 1024 || *port_hi > 65535 || *port_lo > *port_hi) { + syslog(LOG_ERR, + "Unexpected ports contents in %s file.", file); + fclose(fp); + fp = NULL; + return ISC_R_INVALIDFILE; + } + } else if (ret != -ISC_R_DISABLED){ + syslog(LOG_ERR, + "Unexpected ports contents in %s file.", file); + fclose(fp); + fp = NULL; + return ISC_R_INVALIDFILE; + } + /* get excluded ports */ + ret = parse_port_config(buffer_s, "dns-excluded-ports", unports, 17, " "); + if (ret > 0) { + while (unports[i] != '\0') { + no_use_ports[i] = (in_port_t)unports[i]; + i++; + } + } else if (ret != -ISC_R_DISABLED) { + syslog(LOG_ERR, + "Unexpected ports contents in %s file.", file); + fclose(fp); + fp = NULL; + return ISC_R_INVALIDFILE; + } + } + + fclose(fp); + fp = NULL; + return ISC_R_SUCCESS; + } + + syslog(LOG_ERR, + "Open %s fail, return.\n", file); + return ISC_R_FILENOTFOUND; +} + +/*% + * Create a temporary port list to set the initial default set of dispatch + * ports and excluded ports. This is almost meaningless as the application will + * normally set the ports explicitly, but is provided to fill some minor corner + * cases. + */ +static isc_result_t +create_portset_by_range(isc_mem_t *mctx, isc_portset_t **portsetp, in_port_t port_lo, in_port_t port_hi, in_port_t *no_use_ports) { + isc_result_t result; + + result = isc_portset_create(mctx, portsetp); + if (result != ISC_R_SUCCESS) + return (result); + isc_portset_addrange_by_range(*portsetp, port_lo, port_hi, no_use_ports); + + return (ISC_R_SUCCESS); +} + /*% * Create a temporary port list to set the initial default set of dispatch * ports: [1024, 65535]. This is almost meaningless as the application will @@ -1963,6 +2125,9 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_result_t result; isc_portset_t *v4portset = NULL; isc_portset_t *v6portset = NULL; + in_port_t port_lo = 1024; + in_port_t port_hi = 65535; + in_port_t no_use_ports[17] = {0}; REQUIRE(mctx != NULL); REQUIRE(mgrp != NULL && *mgrp == NULL); @@ -2063,14 +2228,23 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, mgr->nv6ports = 0; mgr->magic = DNS_DISPATCHMGR_MAGIC; - result = create_default_portset(mctx, &v4portset); + /* parse port list file, get default set of dispatch ports and excluded ports */ + result = parse_config(conffile, &port_lo, &port_hi, no_use_ports); if (result == ISC_R_SUCCESS) { - result = create_default_portset(mctx, &v6portset); - if (result == ISC_R_SUCCESS) { - result = dns_dispatchmgr_setavailports(mgr, - v4portset, - v6portset); - } + create_portset_by_range(mctx, &v4portset, port_lo, port_hi, no_use_ports); + if (result == ISC_R_SUCCESS) + result = create_portset_by_range(mctx, &v6portset, port_lo, port_hi, no_use_ports); + } + else { + result = create_default_portset(mctx, &v4portset); + if (result == ISC_R_SUCCESS) + result = create_default_portset(mctx, &v6portset); + } + + if (result == ISC_R_SUCCESS) { + result = dns_dispatchmgr_setavailports(mgr, + v4portset, + v6portset); } if (v4portset != NULL) isc_portset_destroy(mctx, &v4portset); diff --git a/lib/isc/include/isc/portset.h b/lib/isc/include/isc/portset.h index 774d6bb..cfd0bcb 100644 --- a/lib/isc/include/isc/portset.h +++ b/lib/isc/include/isc/portset.h @@ -125,6 +125,19 @@ isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo, */ void +isc_portset_addrange_by_range(isc_portset_t *portset, in_port_t port_lo, + in_port_t port_hi, in_port_t *no_use_ports); +/*%< + * Add a subset of [port_lo, port_hi] (inclusive) and no_use_ports(exclusive) to the portset. Ports in the + * subset may or may not be stored in portset. + * + * Requires: + *\li 'portlist' to be valid. + *\li port_lo <= port_hi + *\li no_use_ports > 0 + */ + +void isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo, in_port_t port_hi); /*%< diff --git a/lib/isc/portset.c b/lib/isc/portset.c index 471ca8e..0ebd79f 100644 --- a/lib/isc/portset.c +++ b/lib/isc/portset.c @@ -128,6 +128,31 @@ isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo, } void +isc_portset_addrange_by_range(isc_portset_t *portset, in_port_t port_lo, + in_port_t port_hi, in_port_t *no_use_ports) +{ + in_port_t p; + int i, flag; + REQUIRE(portset != NULL); + REQUIRE(port_lo <= port_hi); + + p = port_lo; + do { + i = 0; + flag = 0; + while (no_use_ports[i] != '\0') { + if (no_use_ports[i] == p) { + flag = 1; + break; + } + i++; + } + if (flag == 0) + portset_add(portset, p); + } while (p++ < port_hi); +} + +void isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo, in_port_t port_hi) {