Python Exercise for Beginners – Getting a list of IP addresses to Whitelist for Cloudflare

 In today’s video we are going to be working on a real-life Python script for Devops.

Many websites in the world today are protected against DDoS attacks by Cloudflare.
Cloudflare provides this protection by serving as an intermediary to all traffic from the web. So instead of a website visitor connecting to the server hosting the website, directly, the visitor connects to one of the servers from Cloudflare. In this way Cloudflare can filter all the requests which look suspicious.

But this only works if an attacker doesn’t bypass the servers from Cloudflare!

If an attacker discovers the IP address of the server hosting the website, then it could attack the website directly!

For that reason, we need to prevent this by whitelisting all the IP addresses from Cloudflare, so that even if an attacker knows what the real IP address of our website, they will not be able to attack it so easily, because their IP address will not be included in the whitelisted list of IP addresses.

Cloudflare provides a url https://www.cloudflare.com/ips-v4 and https://www.cloudflare.com/ips-v6 to download the range of IP addresses(CIDR) used by Cloudflare servers.

We are going to be using Python to read the content of those urls and return as a result a list of strings containing all the CIDR for IPV4 and IPV6.

We will also create a list of unit tests to ensure that our code always returns a non empty list of valid CIDR IP addresses.

def getIPAddresses(url):
      headers = {
        'User-Agent': 'My User Agent 1.0',
        'From': '[email protected]'  # This is another valid field
      }
      result = []
      try:
        req = urllib.request.Request(url, headers=headers)
        with urllib.request.urlopen(req) as f:
            ips = f.read().decode('utf-8').split("n")
            result = ips
      except urllib.error.URLError as e:
        print(e.reason)

      return result      
import urllib
import urllib.request

def whitelistCloudflareIps():
    ips_v4 = getIPAddresses("https://www.cloudflare.com/ips-v4")
    ips_v6 = getIPAddresses("https://www.cloudflare.com/ips-v6")
    return ips_v4 + ips_v6
whitelistCloudflareIps()
['173.245.48.0/20',
 '103.21.244.0/22',
 '103.22.200.0/22',
 '103.31.4.0/22',
 '141.101.64.0/18',
 '108.162.192.0/18',
 '190.93.240.0/20',
 '188.114.96.0/20',
 '197.234.240.0/22',
 '198.41.128.0/17',
 '162.158.0.0/15',
 '104.16.0.0/13',
 '104.24.0.0/14',
 '172.64.0.0/13',
 '131.0.72.0/22',
 '2400:cb00::/32',
 '2606:4700::/32',
 '2803:f800::/32',
 '2405:b500::/32',
 '2405:8100::/32',
 '2a06:98c0::/29',
 '2c0f:f248::/32']
import unittest
import re

class TestGetIpAddressesFromCloudflare(unittest.TestCase):

  def test_whitelistCloudflareIpsForIpv4(self):
    ips = getIPAddresses("https://www.cloudflare.com/ips-v4")
    self.assertTrue(len(ips)> 0)

  def test_whitelistCloudflareIpsForIpv6(self):
    ips = getIPAddresses("https://www.cloudflare.com/ips-v6")
    self.assertTrue(len(ips)> 0)

  def test_whitelistCloudflareIpsForIpv4ShouldReturnValidIpRanges(self):
    ips = getIPAddresses("https://www.cloudflare.com/ips-v4")
    self.assertTrue(len(ips)> 0)
    for ip in ips:
      pattern_ipv4_cidr = "d+.d+.d+.d+/d+"
      result = re.fullmatch(pattern_ipv4_cidr, ip)
      self.assertNotEqual(result, None)

  def test_whitelistCloudflareIpsForIpv6ShouldReturnValidIpRanges(self):
    ips = getIPAddresses("https://www.cloudflare.com/ips-v6")
    self.assertTrue(len(ips)> 0)
    for ip in ips:
      pattern_ipv6_cidr = "(d|[a-f])+:(d|[a-f])+::/d+"
      result = re.fullmatch(pattern_ipv6_cidr, ip)
      self.assertNotEqual(result, None)
if __name__ == '__main__':
   unittest.main(argv=['first-arg-is-ignored'], exit=False)
....
----------------------------------------------------------------------
Ran 4 tests in 0.161s

OK

Resources

Recommended Courses for Data Science

Videos

Source Code

https://github.com/armindocachada/python-for-beginners-exercises/blob/main/Cloudflare.ipynb