My router config is described below. It has several overlapping types of usage security and web policing:
! 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
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.
|
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)
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.
|
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. |