/* * Enumerate the system's network interface addresses and call the callback * for each one. Returns 0 if successful, -1 if trouble. * * This version is our fallback if there's no known way to get the * interface addresses. Just return the standard loopback addresses. */ int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) { struct sockaddr_in addr; struct sockaddr_storage mask; #ifdef HAVE_IPV6 struct sockaddr_in6 addr6; #endif /* addr 127.0.0.1/8 */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = ntohl(0x7f000001); memset(&mask, 0, sizeof(mask)); pg_sockaddr_cidr_mask(&mask, "8", AF_INET); run_ifaddr_callback(callback, cb_data, (struct sockaddr *) & addr, (struct sockaddr *) & mask); #ifdef HAVE_IPV6 /* addr ::1/128 */ memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; addr6.sin6_addr.s6_addr[15] = 1; memset(&mask, 0, sizeof(mask)); pg_sockaddr_cidr_mask(&mask, "128", AF_INET6); run_ifaddr_callback(callback, cb_data, (struct sockaddr *) & addr6, (struct sockaddr *) & mask); #endif return 0; }
/* * Run the callback function for the addr/mask, after making sure the * mask is sane for the addr. */ static void run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data, struct sockaddr * addr, struct sockaddr * mask) { struct sockaddr_storage fullmask; if (!addr) return; /* Check that the mask is valid */ if (mask) { if (mask->sa_family != addr->sa_family) { mask = NULL; } else if (mask->sa_family == AF_INET) { if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY) mask = NULL; } #ifdef HAVE_IPV6 else if (mask->sa_family == AF_INET6) { if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr)) mask = NULL; } #endif } /* If mask is invalid, generate our own fully-set mask */ if (!mask) { pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family); mask = (struct sockaddr *) & fullmask; } (*callback) (addr, mask, cb_data); }
static bool load_rule(int line, const char * dbname, const char * user, const char * ip, const char * mask, int limit) { rule_t * rule; /* error if the segment is already full (no space for another rule) */ if (rules->n_rules == MAX_RULES) elog(ERROR, "too many connection limit rules (max: %d)", MAX_RULES); /* get space for the next rule */ rule = &(rules->rules[rules->n_rules]); memset(rule, 0, sizeof(rule_t)); /* reset the rule (no fields) */ rule->fields = 0; rule->limit = limit; rule->line = line; /* dbname entered */ if (strcmp("all", dbname) != 0) { strcpy(rule->database, dbname); rule->fields |= CHECK_DBNAME; } /* username entered */ if (strcmp("all", user) != 0) { strcpy(rule->user, user); rule->fields |= CHECK_USER; } /* load the IP (see parse_hba_line in hba.c) */ if (strcmp("all", ip) != 0) { int ret; char *ipcopy ; /* IP address parsing */ struct addrinfo hints; struct addrinfo * gai_result; /* process the IP address (without the mask), or a hostname */ ipcopy = pstrdup(ip); if (strchr(ipcopy, '/')) *strchr(ipcopy, '/') = '\0'; hints.ai_flags = AI_NUMERICHOST; hints.ai_family = PF_UNSPEC; hints.ai_socktype = 0; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; /* try to parse the IP address */ ret = pg_getaddrinfo_all(ipcopy, NULL, &hints, &gai_result); if (ret == 0 && gai_result) { memcpy(&(rule->ip), gai_result->ai_addr, gai_result->ai_addrlen); rule->fields |= CHECK_IP; } else if (ret == EAI_NONAME) { strcpy(rule->hostname, ipcopy); rule->fields |= CHECK_HOST; } else { elog(WARNING, "invalid IP address \"%s\": %s", ipcopy, gai_strerror(ret)); pfree(ipcopy); return false; } pfree(ipcopy); if (gai_result) pg_freeaddrinfo_all(hints.ai_family, gai_result); /* Get the netmask */ if (strchr(ip, '/')) { if (strlen(rule->hostname) != 0) { elog(WARNING, "specifying both host name and CIDR mask is invalid: \"%s\"", ip); return false; } else if (pg_sockaddr_cidr_mask(&(rule->mask), strchr(ip, '/') + 1, rule->ip.ss_family) < 0) { elog(WARNING, "invalid CIDR mask in address \"%s\"", ip); return false; } } else if (strlen(rule->hostname) == 0) { if (mask == NULL) { elog(WARNING, "no mask specified for rule %d", rules->n_rules); return false; } ret = pg_getaddrinfo_all(mask, NULL, &hints, &gai_result); if (ret || !gai_result) { elog(WARNING, "invalid IP mask \"%s\": %s", mask, gai_strerror(ret)); if (gai_result) pg_freeaddrinfo_all(hints.ai_family, gai_result); return false; } memcpy(&rule->mask, gai_result->ai_addr, gai_result->ai_addrlen); pg_freeaddrinfo_all(hints.ai_family, gai_result); if (rule->ip.ss_family != rule->mask.ss_family) { elog(WARNING, "IP address and mask do not match"); return false; } } } /* IP address parsing */ /* successfully parsed - at least one field needs to be set (increment) */ if (rule->fields == 0) { elog(WARNING, "rule on line %d is invalid - no value set", line); return false; } else rules->n_rules += 1; return true; }