How to filter a range of IP addresses in a SQL query? - mysql

I am working in a web apps, I made some checking/limitation when user trying to login my application. Now i need to make a white list function to pass these checking make use of user ip address.
I'm trying to write a sql statement to get matched IP address in order to achieve white list. If the sql return data then pass the checking , if not just continue checking.
However, whitelist table in database need to be support 192.168.* or 192.* or (*. *.1.1) .So it will return data and pass if the user ip is 192.X.X.X
SELECT * FROM whitelist WHERE ip_address = $ip;
my sql statement like this.

I agree with #arno comment. If you have limited value to check then use regex instead of database call. It will save you time.
But if you want to call database then I remember that MySql support regex in query also
SELECT
*
FROM
whitelist
WHERE
ip_address REGEXP '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
Above regex is to check all valid IP address. But you can change it based on your requirement.

There is no natural case when you need to match something like *.*.1.1.
IP addresses are mostly matched according to subnets in their CIDR notation. Because this is how networks are organized.
Even simpler, you can convert IP addresses to a long datatype using INET_ATON() and make simple matches using > and <.
Please refer to these solutions:
Is there way to match IP with IP+CIDR straight from SELECT query?
https://dba.stackexchange.com/questions/171044/determining-if-an-ip-is-within-an-ipv4-cidr-block

You can use the LIKE statment:
SELECT * FROM whitelist WHERE ip_address LIKE '192.168.%';
The % character allows any character to replace it, therefore the above query will return IP adress in the range 192.168.0.0 - 192.168.255.255, provided you indeed only have IP adresses in this field.

Related

Select CIDR from IP Range in MySQL

I have a table of IP Ranges and I need to generate a list of networks to reject for a specific country.
So I can generate a list of ip ranges from my db using this.
SELECT
ip_from,
Inet_ntoa(ip_from),
ip_to,
Inet_ntoa(ip_to)
FROM
ip_address_data
WHERE
country_code = 'XX'
LIMIT 1
which generates this result
ip_from inet_ntoa(ip_from) ip_to inet_ntoa(ip_to)
16777472 1.0.1.0 16778239 1.0.3.255
But I need that output in CIDR format and sometimes the range will be more than one row returned like this.
1.0.1.0/24
1.0.2.0/23
Is there any way to dynamically generate these using a select statement? This syntax would be awesome but I'm assuming it'll have to be a stored procedure if it's going to return more than one output row per input row.
SELECT
CONCAT('/sbin/route add -net ', CONVERT_TO_CIDR(ip_from,ip_to), ' reject;') AS command
FROM
ip_info.ip_address_data
WHERE
country_code='XX'
Here's a python script to do the conversion. Just need to convert this to a stored procedure.
Conversion from IP Range to CIDR Mask

how to filter ip address in mysql database which is stored as varchar

I have user table which has username and ip-address.
Suppose I need all data whose IP address is between 5.101.108.0 and 5.101.108.255
How do I write query for it as IP is stored in varchar. Do I need to use regular expression for that as I will have to filter after 5.101.108. ?
Can you give a sample solution as I am not able to think how to filter. Thanks.
You can use INET_ATON() and INET_NTOA() to convert between IP string and integer representation:
SELECT *
FROM ip_addresses
WHERE INET_ATON(ip_address) BETWEEN INET_ATON('5.101.108.0') AND INET_ATON('5.101.108.255');

Query to return rows that match a block of ip addresses?

I'm trying to block certain IP addresses and IP ranges from performing certain actions. Right now, I SELECT * FROM blocked WHERE ip=$_SERVER['REMOTE_ADDR'] and if ->num_rows returns > 0, I redirect the user.
This works with full IP addresses but if I put 199.90.*.* for example, into the database, how might I match that? Also, what would be the best way to store the IPs in the database?
The answer to your question is to use like:
SELECT *
FROM blocked
WHERE $_SERVER['REMOTE_ADDR'] like replace(ip, '*', '%')
The wildcard in like is '%' rather than '*', so this replaces the asterisk with the percent sign. I am guessing that you would actually store the string like '199.199.%.%', but the above is for clarity.
Although this technically solves your problem, it has other issues because MySQL may not use an index for these comparisons (see here). The impact depends on how large the blocked table is. If it has 100 rows, this may not be an issue. If it has 100,000 then it probably is.
An alternative to using wildcards for the blocked table is to have FromIP and ToIP as columns. Then something like "199.199.." would simply be stored as "199.199.000.000" and "199.199.999.999". The query would be:
where $_SERVER['REMOTE_ADDR'] between FromIP and ToIP
And you would have an index on blocked(FromIP, ToIP).
I would first check for full IP address, then mask out the last byte with *, and check for that, then the last 2 bytes, and so on. This way you go from specific to less specific, and if once you get a hit, the IP is blocked. It's probably not the most efficient way, but I guess you have to do it only once, at login-time.
I would store IP addresses for simplicity as strings.
Another solution could be to store IP address as byte-array, but that wouldn't make anything easier I guess, and would be much less maintainable with for example the command-line tool SQL tool.
Your best solution would be to use INET_ATON function.
Given the dotted-quad representation of an IPv4 network address as a string, returns an integer that represents the numeric value of the address in network byte order (big endian).
So, if you want to look for an IP in a certain range, you would use a Query like this:
SELECT * FROM blocked WHERE INET_ATON($_SERVER['REMOTE_ADDR']) between INET_ATON(this_ip) and INET_ATON(this_other_ip).
As I think, the best way to store IPv4 addresses in a MySQL Data base is using that function, to convert them to an int value and store it like that. And If you want to get the IP from it's int representation use INET_NTOA.
Storing IP's as int, the query ends like this:
SELECT * FROM blocked WHERE INET_ATON($_SERVER['REMOTE_ADDR']) between this_ip and this_other_ip.
And instead of using 199.90.*.* use (199.90.0.0).

Getting substring through regexp in mysql query

I have tried all the things like regexp ,substring for getting domain name from uri 'http://start.readingresults.com/RapidResults/vocab_web_alt/reviewResponseAjax.do' but failed to get accurate result.It should show me www.start.readingresults.com.Somatimes uri includes ip address which make me this thing more complex.Such as 192.168.1.10 etc.
Which is more proper way to find domain regexp or substring?
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('http://start.readingresults.com/RapidResults/vocab_web_alt/reviewResponseAjax.do', '//', -1),'/',1);
if your URL having ip address means you have to handle in separate way using SUBSTRING_INDEX
Here the sqlfiddle.
Cheers...

Regex on IP numeric value in MySQL?

Assume a table titled 'transactions'
Typical query: select * from transactions where ip=INET_ATON('127.0.0.1');
I want the ability to do a regex search for all ip's with a particular first octet (i.e. 127) but I can't quite figure out the syntax.
Thanks!
‘transactions.ip’ is already an integer, which is why the questioner is using INT_ATON. It's no good trying to match it directly against a string like/regexp, you would have to convert it back to an IPv4 address first using the reverse function INT_NTOA:
SELECT * FROM transactions WHERE INT_NTOA(ip) LIKE '127.%';
This requires a complete table scan (defeating indexes) to convert and compare.
I want the ability to do a regex search for all ip's with a particular first octet (i.e. 127)
However, in the case where you want to compare against the front part of an IP address, you can take advantage of the fact that the first octet is stored in the most significant bits of the number, and say:
SELECT * FROM transactions WHERE ip BETWEEN INT_NTOA('127.0.0.0') AND INT_NTOA('127.255.255.255');
Which can be done using an index on ‘ip’ so could be considerably more efficient.
You are comparing ip to the result of INET_ATON, which implies that ip is a 32-bit integer. Your operation should be simply...
SELECT * FROM transactions WHERE (longip & 0xFF000000) = (0x7F000000)
This will be far faster than applying a regex to a dotted IP in a string, and faster than the LIKE '127.%' solution.
Like this?
select * from transactions where ip REGEXP "^[1-2][1-9][1-9]"
SELECT * FROM transactions WHERE ip LIKE '127.%';