f9687a2017-12-11Stephen R. van den Berg #pike __REAL_VERSION__ #pragma strict_types
ef04e02017-12-13Stephen R. van den Berg //! Lightweight IPv4 and IPv6 address type that stores the netmask //! and allows simple arithmetic and comparison operators.
f9687a2017-12-11Stephen R. van den Berg 
ebc4212017-12-11Stephen R. van den Berg #define IPV4MAX 0xffffffff
f9687a2017-12-11Stephen R. van den Berg constant is_inet = 1;
ef04e02017-12-13Stephen R. van den Berg //! IP address converted to an integer. //! IPv4 addresses will be 32-bit or less.
f9687a2017-12-11Stephen R. van den Berg int address;
ef04e02017-12-13Stephen R. van den Berg //! Defines the netmask. For both IPv4 and IPv6 addresses, //! @[masklen] will be 128 in case of full addresses.
f9687a2017-12-11Stephen R. van den Berg int masklen;
003ec72017-12-14Stephen R. van den Berg array(int) _encode() { return ({address, masklen}); } void _decode(array(int) x) { address = x[0]; masklen = x[1]; }
ef04e02017-12-13Stephen R. van den Berg //! @param ip //! A string defining an IPv4 or IPv6 address //! with an optional @expr{masklen@} attached. //! If the address is in IPv6 notation, the range //! of the @expr{masklen@} is expected to be //! between @expr{0@} and @expr{128@}. //! If the address is in IPv4 notation, the range //! of the @expr{masklen@} is expected to be //! between @expr{0@} and @expr{32@}.
3675572017-12-13Stephen R. van den Berg variant protected void create(string ip) {
bc48492017-12-12Stephen R. van den Berg  masklen = -1;
ebc4212017-12-11Stephen R. van den Berg  sscanf(ip, "%s/%d", ip, masklen); address = NetUtils.string_to_ip(ip);
bc48492017-12-12Stephen R. van den Berg  if (masklen < 0) masklen = 128; else if (!has_value(ip, ":"))
ebc4212017-12-11Stephen R. van den Berg  masklen += 12 * 8;
f9687a2017-12-11Stephen R. van den Berg }
3675572017-12-13Stephen R. van den Berg 
ef04e02017-12-13Stephen R. van den Berg //! @param ip //! An IPv4 or IPv6 ip address. //! @param masklen //! Defines the netmask, always in the range between @expr{0@} //! and @expr{128@}; i.e. for IPv4 addresses you should //! add @expr{12 * 8@} to the actual IPv4-masklen.
f9687a2017-12-11Stephen R. van den Berg variant protected void create(int ip, void|int masklen) { address = ip;
ef04e02017-12-13Stephen R. van den Berg  this::masklen = zero_type(masklen) ? 16*8 : masklen;
f9687a2017-12-11Stephen R. van den Berg } variant protected void create() { } protected mixed `+(mixed that) { if (!intp(that)) error("Cannot add %O\n", that); this_program n = this_program(); n->masklen = masklen; n->address = address + [int]that; return n; } protected mixed `-(mixed that) { if (intp(that)) return this + -[int]that; else if (objectp(that) && ([object]that)->is_inet) return this->address - [int]([object]that)->address; error("Cannot add %O\n", that); } protected mixed `~() { this_program n = this_program(); n->masklen = masklen; n->address = ~address; return n; } protected mixed `|(mixed that) { this_program n = this_program(); n->masklen = max(masklen, [int]([object]that)->masklen); n->address = address | [int]([object]that)->address; return n; } protected mixed `&(mixed that) { this_program n = this_program(); n->masklen = min(masklen, [int]([object]that)->masklen); n->address = address & [int]([object]that)->address; return n; } protected int(0..1) `<(mixed that) { return objectp(that) ? address < [int]([object]that)->address : intp(that) && address < [int]that; } protected int(0..1) `>(mixed that) { return objectp(that) ? address > [int]([object]that)->address : intp(that) && address > [int]that; } protected int(0..1) `==(mixed that) { return objectp(that) ? address == [int]([object]that)->address && masklen == [int]([object]that)->masklen : address == [int]that; } protected mixed cast(string to) { switch (to) {
ebc4212017-12-11Stephen R. van den Berg  case "string": return NetUtils.ip_to_string(address) + (masklen == 128 ? "" :
bc48492017-12-12Stephen R. van den Berg  sprintf("/%d", masklen - (address <= IPV4MAX && 12*8)));
f9687a2017-12-11Stephen R. van den Berg  case "int": return address; default: return UNDEFINED; } } protected string _sprintf(int fmt, mapping(string:mixed) params) { switch (fmt) { case 'O': return sprintf("Inet(%s)", (string)this); case 's': return (string)this; } return sprintf(sprintf("%%*%c", fmt), params, 0); }