📄 network.c
字号:
b = n / 8; x = memcmp(l, r, b); if (x) return x; lb = ((const u_char *) l)[b]; rb = ((const u_char *) r)[b]; for (b = n % 8; b > 0; b--) { if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb)) { if (IS_HIGHBIT_SET(lb)) return 1; return -1; } lb <<= 1; rb <<= 1; } return 0;}static booladdressOK(unsigned char *a, int bits, int family){ int byte; int nbits; int maxbits; int maxbytes; unsigned char mask; if (family == PGSQL_AF_INET) { maxbits = 32; maxbytes = 4; } else { maxbits = 128; maxbytes = 16; } Assert(bits <= maxbits); if (bits == maxbits) return true; byte = bits / 8; nbits = bits % 8; mask = 0xff; if (bits != 0) mask >>= nbits; while (byte < maxbytes) { if ((a[byte] & mask) != 0) return false; mask = 0xff; byte++; } return true;}/* * These functions are used by planner to generate indexscan limits * for clauses a << b and a <<= b *//* return the minimal value for an IP on a given network */Datumnetwork_scan_first(Datum in){ return DirectFunctionCall1(network_network, in);}/* * return "last" IP on a given network. It's the broadcast address, * however, masklen has to be set to its max btis, since * 192.168.0.255/24 is considered less than 192.168.0.255/32 * * inet_set_masklen() hacked to max out the masklength to 128 for IPv6 * and 32 for IPv4 when given '-1' as argument. */Datumnetwork_scan_last(Datum in){ return DirectFunctionCall2(inet_set_masklen, DirectFunctionCall1(network_broadcast, in), Int32GetDatum(-1));}/* * IP address that the client is connecting from (NULL if Unix socket) */Datuminet_client_addr(PG_FUNCTION_ARGS){ Port *port = MyProcPort; char remote_host[NI_MAXHOST]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->raddr.addr.ss_family) { case AF_INET:#ifdef HAVE_IPV6 case AF_INET6:#endif break; default: PG_RETURN_NULL(); } remote_host[0] = '\0'; ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, remote_host, sizeof(remote_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); clean_ipv6_addr(port->raddr.addr.ss_family, remote_host); PG_RETURN_INET_P(network_in(remote_host, false));}/* * port that the client is connecting from (NULL if Unix socket) */Datuminet_client_port(PG_FUNCTION_ARGS){ Port *port = MyProcPort; char remote_port[NI_MAXSERV]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->raddr.addr.ss_family) { case AF_INET:#ifdef HAVE_IPV6 case AF_INET6:#endif break; default: PG_RETURN_NULL(); } remote_port[0] = '\0'; ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, NULL, 0, remote_port, sizeof(remote_port), NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port)));}/* * IP address that the server accepted the connection on (NULL if Unix socket) */Datuminet_server_addr(PG_FUNCTION_ARGS){ Port *port = MyProcPort; char local_host[NI_MAXHOST]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->laddr.addr.ss_family) { case AF_INET:#ifdef HAVE_IPV6 case AF_INET6:#endif break; default: PG_RETURN_NULL(); } local_host[0] = '\0'; ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen, local_host, sizeof(local_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); clean_ipv6_addr(port->laddr.addr.ss_family, local_host); PG_RETURN_INET_P(network_in(local_host, false));}/* * port that the server accepted the connection on (NULL if Unix socket) */Datuminet_server_port(PG_FUNCTION_ARGS){ Port *port = MyProcPort; char local_port[NI_MAXSERV]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->laddr.addr.ss_family) { case AF_INET:#ifdef HAVE_IPV6 case AF_INET6:#endif break; default: PG_RETURN_NULL(); } local_port[0] = '\0'; ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen, NULL, 0, local_port, sizeof(local_port), NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port)));}Datuminetnot(PG_FUNCTION_ARGS){ inet *ip = PG_GETARG_INET_P(0); inet *dst; dst = (inet *) palloc0(sizeof(inet)); { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pdst = ip_addr(dst); while (nb-- > 0) pdst[nb] = ~pip[nb]; } ip_bits(dst) = ip_bits(ip); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst);}Datuminetand(PG_FUNCTION_ARGS){ inet *ip = PG_GETARG_INET_P(0); inet *ip2 = PG_GETARG_INET_P(1); inet *dst; dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot AND inet values of different sizes"))); else { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); unsigned char *pdst = ip_addr(dst); while (nb-- > 0) pdst[nb] = pip[nb] & pip2[nb]; } ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst);}Datuminetor(PG_FUNCTION_ARGS){ inet *ip = PG_GETARG_INET_P(0); inet *ip2 = PG_GETARG_INET_P(1); inet *dst; dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot OR inet values of different sizes"))); else { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); unsigned char *pdst = ip_addr(dst); while (nb-- > 0) pdst[nb] = pip[nb] | pip2[nb]; } ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst);}static inet *internal_inetpl(inet *ip, int64 addend){ inet *dst; dst = (inet *) palloc0(sizeof(inet)); { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pdst = ip_addr(dst); int carry = 0; while (nb-- > 0) { carry = pip[nb] + (int) (addend & 0xFF) + carry; pdst[nb] = (unsigned char) (carry & 0xFF); carry >>= 8; /* * We have to be careful about right-shifting addend because * right-shift isn't portable for negative values, while simply * dividing by 256 doesn't work (the standard rounding is in the * wrong direction, besides which there may be machines out there * that round the wrong way). So, explicitly clear the low-order * byte to remove any doubt about the correct result of the * division, and then divide rather than shift. */ addend &= ~((int64) 0xFF); addend /= 0x100; } /* * At this point we should have addend and carry both zero if original * addend was >= 0, or addend -1 and carry 1 if original addend was < * 0. Anything else means overflow. */ if (!((addend == 0 && carry == 0) || (addend == -1 && carry == 1))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); } ip_bits(dst) = ip_bits(ip); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); return dst;}Datuminetpl(PG_FUNCTION_ARGS){ inet *ip = PG_GETARG_INET_P(0); int64 addend = PG_GETARG_INT64(1); PG_RETURN_INET_P(internal_inetpl(ip, addend));}Datuminetmi_int8(PG_FUNCTION_ARGS){ inet *ip = PG_GETARG_INET_P(0); int64 addend = PG_GETARG_INT64(1); PG_RETURN_INET_P(internal_inetpl(ip, -addend));}Datuminetmi(PG_FUNCTION_ARGS){ inet *ip = PG_GETARG_INET_P(0); inet *ip2 = PG_GETARG_INET_P(1); int64 res = 0; if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot subtract inet values of different sizes"))); else { /* * We form the difference using the traditional complement, increment, * and add rule, with the increment part being handled by starting the * carry off at 1. If you don't think integer arithmetic is done in * two's complement, too bad. */ int nb = ip_addrsize(ip); int byte = 0; unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); int carry = 1; while (nb-- > 0) { int lobyte; carry = pip[nb] + (~pip2[nb] & 0xFF) + carry; lobyte = carry & 0xFF; if (byte < sizeof(int64)) { res |= ((int64) lobyte) << (byte * 8); } else { /* * Input wider than int64: check for overflow. All bytes to * the left of what will fit should be 0 or 0xFF, depending on * sign of the now-complete result. */ if ((res < 0) ? (lobyte != 0xFF) : (lobyte != 0)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); } carry >>= 8; byte++; } /* * If input is narrower than int64, overflow is not possible, but we * have to do proper sign extension. */ if (carry == 0 && byte < sizeof(int64)) res |= ((int64) -1) << (byte * 8); } PG_RETURN_INT64(res);}/* * clean_ipv6_addr --- remove any '%zone' part from an IPv6 address string * * XXX This should go away someday! * * This is a kluge needed because we don't yet support zones in stored inet * values. Since the result of getnameinfo() might include a zone spec, * call this to remove it anywhere we want to feed getnameinfo's output to * network_in. Beats failing entirely. * * An alternative approach would be to let network_in ignore %-parts for * itself, but that would mean we'd silently drop zone specs in user input, * which seems not such a good idea. */voidclean_ipv6_addr(int addr_family, char *addr){#ifdef HAVE_IPV6 if (addr_family == AF_INET6) { char *pct = strchr(addr, '%'); if (pct) *pct = '\0'; }#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -