Cisco IOS Home Defender configuration

Like many, I've spent 2020 and 2021 trapped at home with teenagers doing virtual schooling. It's been a challenge to (a) police the internet to a sensible level while (b) allowing virtual schooling 8-12 hrs/day. On top of that, I have a Cisco router for a broadband gateway, and it has zero consumer-friendly web controls. Cisco is plenty powerful and robust, mind you, it's just not friendly. But since I'm a certified network enginer (ccie 2795, lapsed) I kind of like a challenge.

My router config is described below. It has several overlapping types of usage security and web policing:

  1. It acts as a DNS server, tied into OpenDNS's free Family Shield service.
  2. DHCP reservations so all devices use predictable IP addresses
  3. object-groups to identify all devices used by a group (eg, "kids", "school", ...)
  4. DNS views so that specific devices are subject to different rules. (eg, blacklist youtube from kids, but allow it for school).
  5. Fuzzy identification of Minecraft traffic
  6. Match Fortnite servers by IP address (see this article)
  7. Use QoS traffic shaping to both restrict bad apps and guarantee bandwidth fairness for my work traffic
  8. Normal NAT and zone-based firewall behavior
  9. Have a big hammer ready to block all internet access when needed
  10. Allow incoming traffic for hosting local minecraft and web servers
  11. Dynamic DNS updates to assist with incoming traffic
  12. ...
Some of the mechanisms are on 24x7. Others are only enabled by time-ranges -- like a bedtime policy. Much of the time, I manually turn things on and off based on family dynamics.
! Game ON!
policy-map INTERNET-FAIRNESS-OUTSIDE
 class CLASS-MINECRAFT
  shape average 256000
! Game OFF!
policy-map INTERNET-FAIRNESS-OUTSIDE
 class CLASS-MINECRAFT
  shape average 8000

IOS configuration walk-through

service tcp-keepalives-in

service tcp-keepalives-out

service timestamps debug datetime msec localtime show-timezone

service timestamps log datetime msec localtime show-timezone

 

hostname c1111

 

aaa new-model

username cisco password sanfran   ! not!

 

logging buffered 100000 notifications

clock timezone CST -6 0

clock summer-time CDT recurring

 

login on-failure log

login on-success log

 

ntp server 50.116.52.97 ! use pool.ntp.org

ntp server 45.32.225.67

ntp server 129.250.35.251

ntp server 23.131.160.7

 

access-list 23 permit 192.168.187.0 0.0.0.255

 

line vty 0 4

 access-class 23 in

 privilege level 15      ! avoid enable pw

 transport input ssh

 

Global best-practice Cisco stuff

ip ddns update method noip

 HTTP

  add http://<email>:<password>@dynupdate.no-ip.com/nic/update?hostname=<h>&myip=<a>

 interval maximum 2 0 0 0

 

Dynamic DNS

 

I use no-ip.com. See Gig0/0/0 for how this is invoked

ip dhcp pool HomeLAN

 network 192.168.187.0 255.255.255.0

 default-router 192.168.187.1

 domain-name beeline.org

 dns-server 192.168.187.1

 lease 14

 

ip dhcp excluded-address 192.168.187.1 192.168.187.50

ip dhcp excluded-address 192.168.187.150 192.168.187.255

 

DHCP on my LAN

 

Set DNS server to self (192.168.187.1). This is required to do DNS filtering in the router.

ip dhcp pool HomeLAN_LukasPhone

 host 192.168.187.70 255.255.255.0

 client-identifier 01d0.7714.4c9f.a6

!

ip dhcp pool HomeLAN_Simi

 host 192.168.187.75 255.255.255.0

 client-identifier 0128.cfe9.1a51.ff

!

ip dhcp pool HomeLAN_Chromebook1

 host 192.168.187.97 255.255.255.0

 client-identifier 0198.2cbc.5582.3c

!

ip dhcp pool HomeLAN_Simi_iPhone

 host 192.168.187.101 255.255.255.0

 client-identifier 0118.f643.e689.ac

!

ip dhcp pool HomeLAN_Alenka_MacBook

 host 192.168.187.64 255.255.255.0

 client-identifier 0114.7dda.ce48.84

!

<and so on...>

 

DHCP reservations

 

These are critical! For every device on your network, grab the client-id from “show ip dhcp bind” and build a static reservation for it. This ensures that the device has a predictable, consistent IP address.

 

A clever person can bypass DHCP reservations by either (a) configuring a static IP or (b) randomizing their MAC address. If you have that problem, expand the “ip dhcp excluded-address” range to include the entire subnet and turn on Cisco IP Source Guard. Unfortunately, this also makes it more difficult to add new devices and guest users to the network. A more mature approach is probably to use multiple SSID’s assigned to different VLANs. Luckily, my kids haven’t figured this out, so I’ve not needed such countermeasures.

 

I use a google spreadsheet to keep track of home devices and periodically review the ARP table to add new reservations.

object-group network Craig

 host 192.168.187.73

 host 192.168.187.105

ip access-list extended MATCH-CRAIG

 permit ip object-group Craig any

 

object-group network Alenka

 host 192.168.187.91

 host 192.168.187.94

ip access-list extended MATCH-ALENKA

 permit ip object-group Alenka any

 

object-group network kids

 host 192.168.187.70

 host 192.168.187.75

 host 192.168.187.74

 host 192.168.187.67

 host 192.168.187.101

ip access-list extended MATCH-KIDS

 permit ip object-group kids any

 

Local Object-groups

 

Using IP assignments from the DHCP reservations, I create one object-group for each class that I want to apply policy to.

 

In my case, Craig is me,  Alenka is my wife, and “kids” are my kids.

 

The access-list for each object-group is used in other places. The object-group itself is also used in other places.

object-group network fortnite

 host 3.226.221.174

 host 34.232.190.196

 host 34.238.57.111

 host 52.86.219.93

 host 52.202.247.6

 host 54.152.247.117

 host 54.172.91.12

 host 34.205.150.50

 <etc...>

 

ip access-list extended MATCH-FORTNITE

 permit ip any object-group fortnite

 

FORTNITE identification

 

As I find gaming servers, I add them to these object-groups.

 

See https://beeline.org/fortnite for a discussion of how harvesting server IPs is done.

 

Although this object-group is named “fortnite”, I wound up putting in xboxlive and twitch and other game IPs into it.

! method A

 

ip access-list extended MATCH-MINECRAFT

 permit tcp any any eq 25565

 

! method B

 

ip access-list extended FUZZY-MINECRAFT

 permit tcp object-group kids any gt 1024

 

route-map PBR permit 10

 match ip address FUZZY-MINECRAFT

 match length 52 52

 set ip qos-group 5

 

MINECRAFT identification

 

Minecraft was a challenge. First I used its well-known port 25565, but it took my kids about ten seconds to bypass that. Then I tried to harvest known server IPs like I do with fortnite, but they don’t identify themselves very well.

 

While looking at Minecraft traffic with Netflow (or Wireshark), I noticed that it sent a lot of packets that were exactly 52 bytes long. This was unusual, and no other protocol does that, certainly not at the same level.

 

On Cisco, matching packet length requires using a route-map and policy-based routing (PBR).

 

ip access-list extended MATCH-KIDS-VPN

 permit udp object-group kids any eq non500-isakmp

 permit udp object-group kids any eq 53

 

VPN identification

 

This is a simple access-list blocking IPSec NAT-T (UDP 4500), but only applied to the kids object-group.

 

Blocking VPN is whack-a-mole. The primary defense is DNS-based (see the "ip dns server" section below). THat stymies most casual attempts to use VPN. A secondary defense is to block common VPN protocol traffic, like "non500-isakmp" aka UDP 4500. I've also caught VPN services using UDP 53, pretending to be DNS traffic to get around hotspot walled gardens.

Unfortunately, a determined individual can bypass both quite easily. Browsers like firefox offer both encrypted DNS and browser-based VPN, a combination that is impossible to block using traditional means.

In the future, VPN will require IP address harvesting, the same technique I use for fortnite. I am also considering an EEM script to kill connections that have certain flow characteristics -- eg, long-lived and a packet rate that suggests gaming as opposed to audio/video conferencing. (it'd be based on a headless netflow collector EEM script project of mine)

 

class-map match-any CLASS-CRAIG

 match access-group name MATCH-CRAIG

 match qos-group 1

 

class-map match-any CLASS-ALENKA

 match access-group name MATCH-ALENKA

 match qos-group 2

 

class-map match-any CLASS-KIDS

 match access-group name MATCH-KIDS

 match qos-group 3

 

class-map match-any CLASS-GAMES

 match qos-group 5

 match access-group name MATCH-MINECRAFT

 match access-group name MATCH-FORTNITE

 

class-map match-any CLASS-KIDS-VPN

 match access-group name MATCH-KIDS-VPN

 match qos-group 6

 

Classification

 

Rather than blocking packets, I use QoS to shape bad traffic down to an unusable level.

 

QoS works on CLASSES. I use ambidextrous classes that can be equally used on the inside interface for classification (with access-lists) and on the outside interface for shaping/queueing (with qos-groups).

 

The next two sections show how inside/outside policy-maps use these classes.

policy-map INTERNET-FAIRNESS

 class CLASS-MINECRAFT

  set qos-group 5

 class CLASS-CRAIG

  set qos-group 1

 class CLASS-ALENKA

  set qos-group 2

 class CLASS-KIDS-VPN

  set qos-group 6

 class CLASS-KIDS

  set qos-group 3

 class class-default

  set qos-group 4

 

QoS policy – inside interface

 

This policy matches the inside view of traffic and it assigns a unique qos-group to each class. The qos-group stays with the packet as it traverses the router. This is important for dealing with NAT, which changes the IPs and renders normal access-lists useless.


If any of these classes overlap, then order is important. E.g., CLASS-KIDS-VPN must occur above CLASS-KIDS in order to properly catch traffic.

 

policy-map INTERNET-FAIRNESS-OUTSIDE

 class CLASS-CRAIG

  shape average 4000000      ! 4 mbps

  fair-queue

  fair-queue queue-limit 50

 class CLASS-ALENKA

  shape average 2000000      ! 2 mbps

  fair-queue

  fair-queue queue-limit 50

 class CLASS-GAMES

  shape average 8000         ! 8 kbps / disabled

 class CLASS-KIDS-VPN

  shape average 8000         ! 8 kbps / disabled

 class CLASS-KIDS

  shape average 2000000      ! 2 mbps

  fair-queue

  fair-queue queue-limit 50

 class class-default

  shape average 2000000      ! 2 mbps

  fair-queue

  fair-queue queue-limit 50

 

QoS policy – outside interface

 

This shapes the various classes in the OUTBBOUND direction. There is no need for an INBOUND filter. By squeezing a protocol’s outbound bandwidth to 8 kbps, it is effectively stopped.

 

If you just want to restrict GAMES and KIDS-VPN, then the other classes wouldn’t need “shape average” commands.

 

I choose to shape ALL classes because my broadband speeds vary a lot by time-of-day and other home LAN traffic was hogging the circuit. E.g., cloud photo backup was causing my work Zoom calls to fail. This approach artificially lowers the bandwidth of each class so that the total committed outbound ratio is at a level that the broadband circuit can deal with, even during bad times.

 

E.g., say you have a broadband circuit with 100 mbps down and 30 mbps up, but you find that during peak hours you can reliably only get 10 mbps up. Unfortunately, Cisco has no way to detect and adjust the available bandwidth from 10-30 mbps based on conditions. So instead I manually carve up the reliable 10 Mbps into different classes. So now cloud backup (class-default) gets at most 2 mbps while I (CLASS-CRAIG) still have my 4 mbps.

 

The downside is that I can’t take advantage of >10 Mbps of upload speeds at the times that my broadband can handle 30 Mbps. But that’s OK. Download speeds are unrestricted, and most people care most about download speeds.

 

interface GigabitEthernet0/0/0

 description Spectrum broadband

 ip ddns update hostname lcw.sytes.net

 ip ddns update noip host dynupdate.no-ip.com

 no ip dhcp client request domain-name

 no ip dhcp client request dns-nameserver

 ip address dhcp

 no ip unreachables

 ip nat outside

 zone-member security OUTSIDE-SPECTRUM

 load-interval 30

 negotiation auto

 service-policy output INTERNET-FAIRNESS-OUTSIDE

 

ip route 0.0.0.0 0.0.0.0 dhcp

 

OUTSIDE interface (broadband)

 

Uses dhcp

Tied into the dynamic DNS update.

NAT outside

Zone-based firewall zone “OUTSIDE-SPECTRUM”

Applies the QoS policy described above

 

I also send the default route to the upstream as learned through DHCP.

interface Vlan10

 description Home Network

 ip flow monitor NETFLOW input

 ip flow monitor NETFLOW output

 ip address 192.168.187.1 255.255.255.0

 ip dns view-group NO-TUBE

 ip nat inside

 zone-member security INSIDE

 ip policy route-map PBR

 service-policy input INTERNET-FAIRNESS

 

INSIDE interface (LAN)

 

Netflow ingress/egress for monitoring

DNS views enforced

NAT inside

Zone-based firewall zone “INSIDE”

Policy-based routing for Fuzzy Minecraft identification

Applies the QoS policy described above

ip dns server

 

ip dns view default

 domain name-server 208.67.220.123

 domain name-server 208.67.222.123

 domain name beeline.org

 

ip dns view NO-TUBE

 domain name-server 208.67.222.222

 domain name-server 208.67.220.220

 domain name beeline.org

 

ip dns view-list NO-TUBE

 view NO-TUBE 10

  restrict source access-group NO-TUBE

 view default 20

 

ip host view NO-TUBE www.youtube.com 2.3.4.5

 

ip access-list standard NO-TUBE

 host 192.168.187.70

 host 192.168.187.75

 host 192.168.187.74

 host 192.168.187.67

 host 192.168.187.101

 

In addition to using QoS to restrict some game traffic, I also wanted to wholesale block web sites by DNS Name.

 

This section globally enables the router’s DNS server with OpenDNS Family Shield DNS servers as the upstream. THese servers provide blanket protection against malware and porn.

 

Next, I create the view-list NO-TUBE that my kids are subjected to. For this, I use OpenDNS Home DNS servers. This is also a free service, but it requires a bit more effort to set up. You must create a free account with OpenDNS and also ensure that you have dynamic DNS properly configured so that OpenDNS can identify which requests are coming from your home network even as your ISP changes your IP address. THe benefit is that you can then choose which categories of DNS queries to allow / disallow, such as Drugs, Pornography, Adware, Web Spam, etc. These are all noble and good categories, but the one you really need is Proxy/Anonymizer which blocks VPN and other circumvention techniques. (see screenshot of my OpenDNS settings)

(instead of OpenDNS, you can DNS filter locally using data from http://dsi.ut-capitole.fr/blacklists/index_en.php or you can move the DNS filtering to a separate device, like pi-hole.)

Next, I locally blacklist DNS entries by adding “ip host” statements for each problematic domain. The IP 2.3.4.5 is a junk IP. The result is that when a device in the NO-TUBE view tries to reach youtube.com, they get a junk IP and their browser hangs. Not pretty, but very effective.

If I had an OpenDNS paid subscription or pi-hole, I would implement this blacklist using those methods instead of local "ip host" entries.

Finally, the access-list determines which devices are subjected to the NO-TUBE DNS rules. I couldn’t get it to work with the kids object-group, but believe that’s a bug with my IOS version. Note that the access-list supports time-range to implement time-of-day / day-of-week restrictions

 

ip access-list extended EMBARGO

 deny ip object-group kids any

 permit ip any any

 

ip access-list extended EMBARGO-TIME

 deny ip object-group kids any time-range window

 permit ip any any

 

time-range window

 absolute start 13:00 13 March 2021 end 17:00 13 March 2021

 

So far, I’ve described ways to surgically identify and restrict certain game apps and wholesale block dns names like youtube.

 

EMBARGO is my big hammer, blocking all Internet access. I sometimes couple it with a time-of-date filter. One of the things greatest in life is applying the big hammer and hearing the lamentations of my kids:

 

interface Vlan 10

 ip access-group EMBARGO in

 

 

flow exporter NETFLOW-EXPORTER

 destination 192.168.187.11

 transport udp 2055

!

flow monitor NETFLOW

 exporter NETFLOW-EXPORTER

 cache timeout active 60

 statistics packet protocol

 statistics packet size

 record netflow-original

 

Netflow is also configured

 

I collect it on a linux server and do various network discovery and monitoring with it.

 

ip nat inside source static tcp 192.168.187.11 80 interface GigabitEthernet0/0/0 80

 

ip nat inside source static tcp 192.168.187.74 25565 interface GigabitEthernet0/0/0 25565

 

 

Like most, my broadband router gets a single public IP address.

 

I NAT two ports of it to inside services. Web traffic (TCP 80) goes to my web server which hosts several virtual domains that are all fronted by cloudflare.  MINECRAFT traffic (TCP 25565) goes to my son’s computer where he hosts a server.

 

ip nat inside source route-map NAT-SPECTRUM interface GigabitEthernet0/0/0 overload

 

route-map NAT-SPECTRUM permit 20

 match ip address LOCAL-SUBNETS

 match interface GigabitEthernet0/0/0

 

ip access-list extended LOCAL-SUBNETS

 permit ip 192.168.187.0 0.0.0.255 any

 

The final NAT statement is the general purpose PAT for all outbound traffic. My route-map for more granular control since I have multiple ISP’s and tunnel interfaces. If you only have an inside and outside, there’s no need for a route-map.

 

ip access-list extended INSIDE-TO-SPECTRUM

 permit ip any any

 

ip access-list extended SPECTRUM-TO-INSIDE

 permit tcp any host 192.168.187.74 eq 25565

 permit tcp any host 192.168.187.11 eq www

 

class-map type inspect match-all INSIDE-TO-SPECTRUM

 match access-group name INSIDE-TO-SPECTRUM

 

class-map type inspect match-any SPECTRUM-TO-INSIDE

 match access-group name SPECTRUM-TO-INSIDE

 

policy-map type inspect INSIDE-TO-SPECTRUM

 class type inspect INSIDE-TO-SPECTRUM

  inspect

 class class-default

  drop log

 

policy-map type inspect SPECTRUM-TO-INSIDE

 class type inspect SPECTRUM-TO-INSIDE

  inspect

 class class-default

  drop log

 

policy-map type inspect BLIND-PERMIT

 class class-default

  pass

 

zone security INSIDE

zone security OUTSIDE-SPECTRUM

 

zone-pair security INSIDE-TO-SPECTRUM source INSIDE destination OUTSIDE-SPECTRUM

 service-policy type inspect INSIDE-TO-SPECTRUM

 

zone-pair security SPECTRUM-TO-INSIDE source OUTSIDE-SPECTRUM destination INSIDE

 service-policy type inspect SPECTRUM-TO-INSIDE

 

zone-pair security INSIDE-TO-SELF source INSIDE destination self

 service-policy type inspect BLIND-PERMIT

 

zone-pair security SELF-TO-INSIDE source self destination INSIDE

 service-policy type inspect BLIND-PERMIT

 

Cisco’s ZONE-BASED FIREWALL (ZBF)

 

ZBF is Cisco’s way of punishing us.

 

I use the same name for the access-list, class-map, and policy-map, even though those are distinct objects.

 

The SPECTRUM-TO-INSIDE access-list is the only thing that does anything interesting – it permits outside traffic in for the two hosts services described under NAT.   Since ZBF happens after NAT, the access-lists must match the inside IPs.