Net functions behave slightly different for IPv4 from IPv6. Why? - google-bigquery

I'm using BigQuery to truncate IPv4 & IP46 IP addresses. By that I mean I want to drop the part that might be used to identify a real person.
Here's some demo code:
select *,
NET.IP_TO_STRING(NET.IP_TRUNC(NET.IP_FROM_STRING(v.IPv4Address), 24)),
NET.IP_TO_STRING(NET.IP_TRUNC(NET.IP_FROM_STRING(v.IPv6Address), 64))
from (
select struct(
"254.34.78.20" as `IPV4Address`,
"2a02:c7e:3f0d:e00:48e:abff:d697:9cc2" as `IPv6Address`
) as v
)
It returns:
v
f0_
f1_
{ "IPV4Address": "254.34.78.20", "IPv6Address": "2a02:c7e:3f0d:e00:48e:abff:d697:9cc2" }
254.34.78.0
2a02:c7e:3f0d:e00::
I'd simply like to know why these functions return a 0 for the truncated portion of the IPv4 address but nothing for the truncated portion of the IPv6 address.
I know this isn't really a BigQuery question per se as its more about networks and I suspect BigQuery is just doing what any other such library would do... but interested to know why this is nonetheless. Maybe I'll tag it with IPv6 too

I'd simply like to know why these functions return a 0 for the
truncated portion of the IPv4 address but nothing for the truncated
portion of the IPv6 address.
It is returning 0 for the truncated part of the IPv6 address.
IPv6 addresses can have several forms, but the canonical form requires you to shorten the longest run of 0 fields with a double colon (::). That is at the end of your address 2a02:c7e:3f0d:e00::, and that means it is 2a02:c7e:3f0d:e00:0:0:0:0 properly shortened.

Related

Find Subnet Address given IP Address and Prefix Length in Oracle 12c/ PL SQL

Given IP Address (example: 12.12.12.12/24) return prefix IP address (example: 12.12.12.0).
How can we make these conversions in SQL?
I was trying to string together a method by converting IP address to binary and then ANDing them. There are a tonne of examples in general, nothing that works for PL/SQL. Any help is appreciated.
Here's a way using REGEXP_REPLACE(). The regular expression describes the string, with the 'remembered' part in parentheses. The remembered part is everything up to and including the last period in the string. We don;t want the rest of the string. The replace part of the call replaces with the first remembered part (denoted as \1) followed by the 0.
SELECT REGEXP_REPLACE('12.12.12.12/24', '(.*\.).*', '\10') new_ip
from dual;
NEW_IP
----------
12.12.12.0
1 row selected.

Postgres "is not contained by" operator for IP addresses or inet types

Postgres has an operator for determining whether an IP address is contained by a given range, for example:
SELECT * FROM clients WHERE ip_address <<= inet '10.0.0.0/16';
How could I filter for the reverse set, the set of addresses not in that subnet? The documentation of net functions does not seem to have an operator that can do this. https://www.postgresql.org/docs/12/functions-net.html
Use NOT:
SELECT *
FROM clients
WHERE NOT (ip_address <<= inet '10.0.0.0/16');
Parentheses are not necessary, inet operators have higher precedence than boolean ones.

Can IP Port use as alphanumeric instead of numeric?

It is possible if I do like this?
http://myurl:abc
Port : abc instead of 123
No.
According to RFC3986, the port part of a URI is defined thus (my bold):
The port subcomponent of authority is designated by an optional port number in decimal following the host and delimited from it by a single colon (":") character.
That RFC has been updated by both RFC6874 and RFC7320, but neither of those effect any changes on the relevant section.
No, that cannot be the case. The port is a number always, as per specification.

Sort IP address column

I'm having one column named IPAddress in my table. I want to get IPAddress in sorted order.
IP Address:
8.123.10.124
192.23.34.45
If I use Order by IPAddress, i will get output as
192.23.34.45
8.123.10.124
Because order by sort it as string.
But I want output as
8.123.10.124
192.23.34.45
How to write a query for the same.
Is there any way to split a string in HSQL
You first need to convert the IP Address from string to int. For example, IP address 1.1.1.1 would be 001001001001 you can use following logic
while(ip[j]!='\0')
{
if(ip[j]!='.')
a[i]=a[i]*10+ip[j]-'0';
else
i++;
j++;
}
After that you can multiple a[0],a[1].... by appropriate numbers (1e9,1e6,1e3,1e0) and add .
However, you need to take some precaution such string which stores IP address doesn't have any white space saved with them and use unsigned long long int to store IP address in integer form

Mysql field name within regular expression

I have the following table
Table bots{
ip_address varchar(15),
bot_name varchar(32)
}
Given that some bots have static ips and others won't, the table has entries such as 192.168.0 and 192.168.1.15
Now I have to see if a given ip belongs to a bot. I was thinking something along these lines
SELECT bot_name
FROM bots
WHERE __input_ip__ REGEXP '^ip_address'
but this won't work for the obvious reason that it is looking for a string that starts with ip_address.
So my question is, how can I include a field name within a sql regular expression ?
You might want to consider storing the IP address as an INT UNSIGNED. Also store the netmask so you can tell the difference between a static address and a subnet.
INSERT INTO bots (ipaddress, netmask, bot_name)
VALUES (INET_ATOI('192.168.1.0'), INET_ATOI('255.255.255.0'), 'Wall-E');
Then you can query to see if an input IP address matches:
SELECT bot_name
FROM bots
WHERE __input_ip__ & netmask = ipaddress & netmask;
Using integers for IP addresses instead of CHAR(15) is a common optimization. Even storing the 8 bytes for the IP address and the netmask is little more than half the storage of the CHAR(15). And the bitwise operations are likely to be a lot faster than the regular expression matching, and it's easier to avoid the corner cases like in #Gumbo's comment.
Try this:
SELECT bot_name
FROM bots
WHERE __input_ip__ REGEXP concat('^', replace(ip_address, '.', '\.'))
(This is a response to Andrew's answer but doesn't fit in a comment.)
WHERE __input_ip__ REGEXP concat('^', replace(ip_address, '.', '\.'))
Good plan, except that in MySQL \ is a (non-standard SQL) string literal escape, so to get one in the regexp you'd probably need '\\\.'!
...except in ANSI mode it wouldn't. Argh! To be compatible you'd have to get the backslash another way:
WHERE __input_ip__ REGEXP CONCAT('^', REPLACE(ip_address, '.', CHAR(92, 46)))
Ugh. Maybe better to forget regex and do it with string ops:
WHERE LEFT(__input_ip__, CHAR_LENGTH(ip_address))=__input_ip__