update
This commit is contained in:
parent
ac6c03c715
commit
d0d1667991
144 changed files with 25370 additions and 390 deletions
|
|
@ -1,22 +0,0 @@
|
|||
# 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
|
||||
55
CLAUDE.md
55
CLAUDE.md
|
|
@ -138,7 +138,7 @@ above the `fasttrack-connection` rule on both endpoints. Documented in
|
|||
```
|
||||
verona ──AF11── climax ──AF24── core ──AF11── culleoka
|
||||
│ │ │
|
||||
│ AF11 │ AF11 │ AF11 (DOWN: power injector unplugged)
|
||||
│ 5GHz │ AF11 │ AF11 (DOWN: power injector unplugged)
|
||||
│ │ │
|
||||
494 newhope ──AF24── lowry
|
||||
│
|
||||
|
|
@ -146,7 +146,7 @@ verona ──AF11── climax ──AF24── core ──AF11── culleoka
|
|||
│
|
||||
982
|
||||
```
|
||||
Wait — that diagram's links are: climax↔494 (AF11), core↔newhope (AF11),
|
||||
Wait — that diagram's links are: climax↔494 (5 GHz airMAX, **not** AF11 — see below), 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.
|
||||
|
|
@ -179,7 +179,7 @@ fasttrack-bypass rules in both directions on both routers.
|
|||
|--|--|--|--|--|--|
|
||||
| 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↔494 | 5 GHz airMAX | 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 |
|
||||
|
|
@ -194,12 +194,32 @@ sides symmetrically when changing l2mtu** — single-side raises usually work
|
|||
because Ethernet receivers accept anything ≤ their cap, but symmetric is
|
||||
the rule.
|
||||
|
||||
### climax↔494 backhaul is 5 GHz airMAX, not AF11
|
||||
Old docs called this hop AF11; it is actually a Ubiquiti airMAX AC PtP
|
||||
pair (SSID `vntx_pr_494`, WPA2, 40 MHz wide): AP **"Climax to 494"**
|
||||
(PBE-5AC-500) at `10.250.1.69` on the climax side, station **"494 to
|
||||
Climax"** (PBE-5AC-400) at `10.250.1.66` on the 494 side. Both answer
|
||||
SNMP v1 (`kdyyJrT0Mm`, airMAX MIB `1.3.6.1.4.1.41112.1.4`); added to
|
||||
`radios.yaml` 2026-07-17. The station's mgmt IP (and the whole 494
|
||||
tower) is only reachable **across this RF link** — when changing the
|
||||
channel, first make sure the station's frequency scan list covers the
|
||||
target, then change the AP (climax side), which stays reachable for
|
||||
rollback either way.
|
||||
|
||||
2026-07-17 flap incident: link ran on **5260 MHz (DFS)**; associations
|
||||
dropped for 40–90 s every 45–130 min (OSPF 40 s dead-interval timeouts
|
||||
on both routers; ethernet ports never dropped, radios never rebooted —
|
||||
association-uptime SNMP counters matched each OSPF flap). Local 5 GHz
|
||||
survey: climax APs on 5335/5545/5575 (airMAX) + 5750/5775 (ePMP), 494
|
||||
ePMP omni on 5800 → U-NII-1 (5170–5250) was empty at both towers and
|
||||
is non-DFS, so the fix was moving the PtP there.
|
||||
|
||||
### 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 is off on every
|
||||
wireless backbone interface (AF11/AF24/60GHz)** — the global timers
|
||||
(`/routing/bfd/configuration` = 200ms×5 = 1s detection) are too
|
||||
aggressive for AF RF: a single >1s burst tore down OSPF on
|
||||
aggressive for backhaul RF: a single >1s burst tore down OSPF on
|
||||
climax↔494 every ~15–40 min until `use-bfd=false` was applied to both
|
||||
ends 2026-05-09. Wired fiber links may keep BFD if desired. If
|
||||
sub-second failover on a wireless link is genuinely needed, also
|
||||
|
|
@ -241,6 +261,33 @@ 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.
|
||||
|
||||
### graham's home network — multi-WAN failover (recursive check-gateway)
|
||||
Home (RB5009, `10.0.19.254`, **not** in `routers.yaml` — use a temp
|
||||
config with the same default creds to reach it via mikrotik-tool) fails
|
||||
over between TMO (distance 1), VNTX/verona (distance 2), and Starlink
|
||||
(distance 3, disabled) using the standard ROS recursive pattern, applied
|
||||
2026-07-17 via `mikrotik-tool/home-recursive-failover.rsc`:
|
||||
- Probe pins: `4.2.2.1/32→192.168.12.1%ether6-tmobile`,
|
||||
`4.2.2.2/32→204.110.191.30%ether5-vntx-static`,
|
||||
`4.2.2.3/32→192.168.1.1%ether7-starlink`, all `scope=10`, **no
|
||||
check-gateway on the pins** — they stay active whenever the interface
|
||||
has link, gluing probes to their WAN regardless of route state.
|
||||
- Defaults: `gateway=4.2.2.x target-scope=11 check-gateway=ping` — the
|
||||
check pings the probe IP through the pin; ~20s to go inactive, first
|
||||
success to return. `tmo table default` (eweka policy routing) has the
|
||||
same check so it falls back to main when TMO upstream dies.
|
||||
|
||||
**Do not reintroduce netwatch enable/disable failover scripts.** The old
|
||||
design (netwatch 2s/1s single-packet → `/ip route disable`) deadlocked:
|
||||
`disabled=yes` persists across reboots, and the probe was only tied to
|
||||
the VNTX path while its pin was active — so the verona hotspot-binding
|
||||
loss (verona pingable, transit dead) left the route disabled forever,
|
||||
and probes leaked out other WANs giving false "up" (TMO netwatch read up
|
||||
with the TMO interface physically down). Same lesson as the fleet BFD
|
||||
incident: 1-2s detection on AF RF with >1s bursts causes false failover;
|
||||
10–20s check-gateway damping is intentional.
|
||||
|
||||
|
||||
### 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
|
||||
|
|
|
|||
198
backups/494-to-climax_STA_10.250.1.66_system.cfg.2026-07-17
Normal file
198
backups/494-to-climax_STA_10.250.1.66_system.cfg.2026-07-17
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=8 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group14-sha1 ubnt@10.250.1.66 cat /tmp/system.cfg
|
||||
aaa.1.radius.acct.1.port=1813
|
||||
aaa.1.radius.acct.1.status=disabled
|
||||
aaa.1.radius.auth.1.port=1812
|
||||
aaa.1.status=disabled
|
||||
aaa.1.wpa.psk=0000:0000
|
||||
aaa.status=disabled
|
||||
airview.status=enabled
|
||||
bridge.1.devname=br0
|
||||
bridge.1.port.1.devname=eth0
|
||||
bridge.1.port.1.status=enabled
|
||||
bridge.1.port.2.devname=ath0
|
||||
bridge.1.port.2.status=enabled
|
||||
bridge.1.status=enabled
|
||||
bridge.1.stp.status=disabled
|
||||
bridge.status=enabled
|
||||
discovery.beacon.status=enabled
|
||||
discovery.cdp.status=disabled
|
||||
discovery.lldp.status=enabled
|
||||
discovery.status=enabled
|
||||
ebtables.status=enabled
|
||||
ebtables.sys.eap.1.devname=ath0
|
||||
ebtables.sys.eap.1.status=enabled
|
||||
ebtables.sys.eap.status=enabled
|
||||
ebtables.sys.fw.status=disabled
|
||||
ebtables.sys.fw6.status=disabled
|
||||
ebtables.sys.status=enabled
|
||||
gui.language=en_US
|
||||
gui.network.advanced.status=disabled
|
||||
httpd.https.port=443
|
||||
httpd.https.status=enabled
|
||||
httpd.port=80
|
||||
httpd.session.timeout=900
|
||||
httpd.status=enabled
|
||||
igmpproxy.status=disabled
|
||||
iptables.status=disabled
|
||||
iptables.sys.portfw.status=disabled
|
||||
iptables.sys.status=enabled
|
||||
netconf.1.autoip.status=disabled
|
||||
netconf.1.devname=ath0
|
||||
netconf.1.mtu=1500
|
||||
netconf.1.status=enabled
|
||||
netconf.1.up=enabled
|
||||
netconf.2.autoip.status=disabled
|
||||
netconf.2.autoneg=enabled
|
||||
netconf.2.devname=eth0
|
||||
netconf.2.flowcontrol.rx.status=enabled
|
||||
netconf.2.flowcontrol.tx.status=enabled
|
||||
netconf.2.mtu=1500
|
||||
netconf.2.status=enabled
|
||||
netconf.2.up=enabled
|
||||
netconf.3.autoip.status=disabled
|
||||
netconf.3.devname=br0
|
||||
netconf.3.ip6.status=enabled
|
||||
netconf.3.ip=10.250.1.66
|
||||
netconf.3.mtu=1500
|
||||
netconf.3.netmask=255.255.255.248
|
||||
netconf.3.role=mlan
|
||||
netconf.3.status=enabled
|
||||
netconf.status=enabled
|
||||
netmode=bridge
|
||||
ntpclient.1.server=0.us.pool.ntp.org
|
||||
ntpclient.1.status=enabled
|
||||
ntpclient.status=enabled
|
||||
pppoe-relay.status=disabled
|
||||
pwdog.delay=300
|
||||
pwdog.period=300
|
||||
pwdog.retry=3
|
||||
pwdog.status=disabled
|
||||
radio.1.ack.auto=enabled
|
||||
radio.1.ackdistance=600
|
||||
radio.1.acktimeout=35
|
||||
radio.1.antenna.gain=25
|
||||
radio.1.antenna.id=1
|
||||
radio.1.atpc.sta.status=enabled
|
||||
radio.1.atpc.status=disabled
|
||||
radio.1.atpc.threshold=36
|
||||
radio.1.cable.loss=0
|
||||
radio.1.center.1.freq=5165
|
||||
radio.1.chanbw=0
|
||||
radio.1.cmsbias=0
|
||||
radio.1.countrycode=840
|
||||
radio.1.cwm.enable=0
|
||||
radio.1.cwm.mode=1
|
||||
radio.1.devname=ath0
|
||||
radio.1.dfs.slave=1
|
||||
radio.1.dfs.status=enabled
|
||||
radio.1.ff_cap_rep=0
|
||||
radio.1.freq=5165
|
||||
radio.1.ieee_mode=auto
|
||||
radio.1.low_txpower_mode=disabled
|
||||
radio.1.mode=managed
|
||||
radio.1.obey=enabled
|
||||
radio.1.polling=enabled
|
||||
radio.1.polling_ff_dl_ratio=50
|
||||
radio.1.polling_ff_dur=0
|
||||
radio.1.polling_ff_flex=0
|
||||
radio.1.polling_ff_sta_rx_rssi_th=0
|
||||
radio.1.pollingnoack=0
|
||||
radio.1.pollingpri=2
|
||||
radio.1.ptpmode=1
|
||||
radio.1.rc_mode=0
|
||||
radio.1.reg_obey=enabled
|
||||
radio.1.rx_sensitivity=-96
|
||||
radio.1.scan_list.status=disabled
|
||||
radio.1.scanbw.status=disabled
|
||||
radio.1.status=enabled
|
||||
radio.1.txpower=20
|
||||
radio.countrycode=840
|
||||
radio.status=enabled
|
||||
resolv.host.1.name=494 to Climax
|
||||
resolv.host.1.status=enabled
|
||||
resolv.nameserver.1.ip=204.110.191.240
|
||||
resolv.nameserver.1.status=enabled
|
||||
resolv.nameserver.2.ip=204.110.191.250
|
||||
resolv.nameserver.2.status=enabled
|
||||
resolv.nameserver.status=enabled
|
||||
route.1.devname=br0
|
||||
route.1.gateway=10.250.1.70
|
||||
route.1.ip=0.0.0.0
|
||||
route.1.netmask=0
|
||||
route.1.status=enabled
|
||||
route.status=enabled
|
||||
snmp.community=kdyyJrT0Mm
|
||||
snmp.contact=vntx
|
||||
snmp.location=vntx
|
||||
snmp.status=enabled
|
||||
sshd.auth.passwd=enabled
|
||||
sshd.port=22
|
||||
sshd.status=enabled
|
||||
syslog.remote.port=514
|
||||
syslog.remote.status=disabled
|
||||
syslog.status=enabled
|
||||
system.airosx.prov.status=enabled
|
||||
system.autosend_crash_reports=disabled
|
||||
system.cfg.editor.webui=2026-06-27T20:28:48.251Z
|
||||
system.cfg.version=65547
|
||||
system.date.status=disabled
|
||||
system.external.reset=enabled
|
||||
system.height=0
|
||||
system.latitude=33.1801
|
||||
system.leds.nightmode=disabled
|
||||
system.longitude=-96.498
|
||||
system.poe_passthrough=disabled
|
||||
system.timezone.name=America/Chicago
|
||||
system.timezone=CST6CDT,M3.2.0,M11.1.0
|
||||
telnetd.port=23
|
||||
telnetd.status=disabled
|
||||
tshaper.status=disabled
|
||||
unms.status=enabled
|
||||
unms.ui_url=https://uisp.vntx.net
|
||||
unms.uri=wss://uisp.vntx.net:443+NHjWcWdwuHlhAfrBqATpt6_Tz3-Sv-xYka64WI4hBGcAAAAA+allowUntrustedCertificate
|
||||
update.check.status=enabled
|
||||
users.1.name=ubnt
|
||||
users.1.password=$1$.vDPgZgX$bg0TprBhNiUYo4uDoMwvi1
|
||||
users.1.status=enabled
|
||||
users.2.gid=100
|
||||
users.2.shell=/bin/false
|
||||
users.2.status=disabled
|
||||
users.2.uid=100
|
||||
users.status=enabled
|
||||
wireless.1.ampdu.frames=32
|
||||
wireless.1.ampdu.status=enabled
|
||||
wireless.1.amsdu=3
|
||||
wireless.1.devname=ath0
|
||||
wireless.1.hide_ssid=disabled
|
||||
wireless.1.l2_isolation=disabled
|
||||
wireless.1.mac_acl.policy=allow
|
||||
wireless.1.mac_acl.status=disabled
|
||||
wireless.1.mcast.enhance=0
|
||||
wireless.1.rate.auto=enabled
|
||||
wireless.1.rate.mcs=-1
|
||||
wireless.1.security.type=none
|
||||
wireless.1.signal_led1=94
|
||||
wireless.1.signal_led2=80
|
||||
wireless.1.signal_led3=73
|
||||
wireless.1.signal_led4=65
|
||||
wireless.1.signal_led_status=enabled
|
||||
wireless.1.ssid=vntx_pr_494
|
||||
wireless.1.status=enabled
|
||||
wireless.1.wds.status=enabled
|
||||
wireless.status=enabled
|
||||
wpasupplicant.device.1.devname=ath0
|
||||
wpasupplicant.device.1.profile=AUTO
|
||||
wpasupplicant.device.1.status=enabled
|
||||
wpasupplicant.profile.1.name=AUTO
|
||||
wpasupplicant.profile.1.network.1.eap.1.status=disabled
|
||||
wpasupplicant.profile.1.network.1.key_mgmt.1.name=WPA-PSK
|
||||
wpasupplicant.profile.1.network.1.pairwise.1.name=CCMP
|
||||
wpasupplicant.profile.1.network.1.priority=100
|
||||
wpasupplicant.profile.1.network.1.proto.1.name=RSN
|
||||
wpasupplicant.profile.1.network.1.psk=0000:0000
|
||||
wpasupplicant.profile.1.network.1.ssid=vntx_pr_494
|
||||
wpasupplicant.profile.1.network.1.status=enabled
|
||||
wpasupplicant.profile.1.network.2.key_mgmt.1.name=NONE
|
||||
wpasupplicant.profile.1.network.2.priority=2
|
||||
wpasupplicant.profile.1.network.2.status=disabled
|
||||
wpasupplicant.status=enabled
|
||||
204
backups/climax-to-494_AP_10.250.1.69_system.cfg.2026-07-17
Normal file
204
backups/climax-to-494_AP_10.250.1.69_system.cfg.2026-07-17
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=8 -o NumberOfPasswordPrompts=1 -o PreferredAuthentications=password -o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group14-sha1 ubnt@10.250.1.69 cat /tmp/system.cfg
|
||||
aaa.status=enabled
|
||||
aaa.1.devname=ath0
|
||||
aaa.1.radius.acct.1.port=1813
|
||||
aaa.1.radius.acct.1.status=disabled
|
||||
aaa.1.radius.auth.1.port=1812
|
||||
aaa.1.radius.auth.1.status=disabled
|
||||
aaa.1.ssid=vntx_pr_494
|
||||
aaa.1.status=enabled
|
||||
aaa.1.wpa.key.1.mgmt=WPA-PSK
|
||||
aaa.1.wpa.mode=2
|
||||
aaa.1.wpa.psk=0000:0000
|
||||
aaa.1.wpa.1.pairwise=CCMP
|
||||
airview.status=enabled
|
||||
bridge.status=enabled
|
||||
bridge.1.devname=br0
|
||||
bridge.1.port.1.devname=eth0
|
||||
bridge.1.port.1.status=enabled
|
||||
bridge.1.port.2.devname=ath0
|
||||
bridge.1.port.2.status=enabled
|
||||
bridge.1.status=enabled
|
||||
bridge.1.stp.status=disabled
|
||||
discovery.beacon.status=enabled
|
||||
discovery.cdp.status=enabled
|
||||
discovery.lldp.status=enabled
|
||||
discovery.status=enabled
|
||||
ebtables.status=enabled
|
||||
ebtables.sys.eap.status=enabled
|
||||
ebtables.sys.eap.1.devname=ath0
|
||||
ebtables.sys.eap.1.status=enabled
|
||||
ebtables.sys.fw.status=disabled
|
||||
ebtables.sys.fw6.status=disabled
|
||||
ebtables.sys.status=enabled
|
||||
gui.language=en_US
|
||||
gui.network.advanced.status=disabled
|
||||
httpd.https.port=443
|
||||
httpd.https.status=enabled
|
||||
httpd.https.tlsv1=enabled
|
||||
httpd.port=80
|
||||
httpd.session.timeout=900
|
||||
httpd.status=enabled
|
||||
igmpproxy.status=disabled
|
||||
iptables.status=disabled
|
||||
iptables.sys.portfw.status=disabled
|
||||
iptables.sys.status=enabled
|
||||
netconf.status=enabled
|
||||
netconf.1.autoip.status=disabled
|
||||
netconf.1.devname=ath0
|
||||
netconf.1.mtu=1500
|
||||
netconf.1.status=enabled
|
||||
netconf.1.up=enabled
|
||||
netconf.2.autoip.status=disabled
|
||||
netconf.2.autoneg=enabled
|
||||
netconf.2.devname=eth0
|
||||
netconf.2.flowcontrol.rx.status=enabled
|
||||
netconf.2.flowcontrol.tx.status=enabled
|
||||
netconf.2.mtu=1500
|
||||
netconf.2.status=enabled
|
||||
netconf.2.up=enabled
|
||||
netconf.3.autoip.status=disabled
|
||||
netconf.3.devname=br0
|
||||
netconf.3.ip=10.250.1.69
|
||||
netconf.3.ip6.status=enabled
|
||||
netconf.3.mtu=1500
|
||||
netconf.3.netmask=255.255.255.248
|
||||
netconf.3.role=mlan
|
||||
netconf.3.status=enabled
|
||||
netmode=bridge
|
||||
ntpclient.status=enabled
|
||||
ntpclient.1.server=0.us.pool.ntp.org
|
||||
ntpclient.1.status=enabled
|
||||
pppoe-relay.status=disabled
|
||||
pwdog.delay=300
|
||||
pwdog.period=300
|
||||
pwdog.retry=3
|
||||
pwdog.status=disabled
|
||||
radio.countrycode=840
|
||||
radio.status=enabled
|
||||
radio.1.ack.auto=enabled
|
||||
radio.1.ackdistance=600
|
||||
radio.1.acktimeout=35
|
||||
radio.1.antenna.gain=27
|
||||
radio.1.antenna.id=1
|
||||
radio.1.atpc.sta.status=enabled
|
||||
radio.1.atpc.status=disabled
|
||||
radio.1.atpc.threshold=36
|
||||
radio.1.cable.loss=0
|
||||
radio.1.center.1.freq=5270
|
||||
radio.1.chanbw=40
|
||||
radio.1.cmsbias=0
|
||||
radio.1.countrycode=840
|
||||
radio.1.cwm.enable=0
|
||||
radio.1.cwm.mode=1
|
||||
radio.1.devname=ath0
|
||||
radio.1.dfs.status=enabled
|
||||
radio.1.ff_cap_rep=0
|
||||
radio.1.freq=5260
|
||||
radio.1.ieee_mode=11acvht40
|
||||
radio.1.low_txpower_mode=disabled
|
||||
radio.1.mode=master
|
||||
radio.1.obey=enabled
|
||||
radio.1.polling=enabled
|
||||
radio.1.polling_ff_dl_ratio=50
|
||||
radio.1.polling_ff_dur=0
|
||||
radio.1.polling_ff_flex=0
|
||||
radio.1.polling_ff_sta_rx_rssi_th=0
|
||||
radio.1.polling_11ac_11n_compat=0
|
||||
radio.1.pollingnoack=0
|
||||
radio.1.pollingpri=2
|
||||
radio.1.ptpmode=1
|
||||
radio.1.rc_mode=0
|
||||
radio.1.reg_obey=disabled
|
||||
radio.1.rx_sensitivity=-96
|
||||
radio.1.scan_list.status=disabled
|
||||
radio.1.scanbw.status=disabled
|
||||
radio.1.status=enabled
|
||||
radio.1.txpower=24
|
||||
resolv.host.1.name=Climax to 494
|
||||
resolv.host.1.status=enabled
|
||||
resolv.nameserver.status=enabled
|
||||
resolv.nameserver.1.ip=204.110.191.240
|
||||
resolv.nameserver.1.status=enabled
|
||||
resolv.nameserver.2.ip=204.110.191.250
|
||||
resolv.nameserver.2.status=enabled
|
||||
route.status=enabled
|
||||
route.1.devname=br0
|
||||
route.1.gateway=10.250.1.70
|
||||
route.1.ip=0.0.0.0
|
||||
route.1.netmask=0
|
||||
route.1.status=enabled
|
||||
snmp.community=kdyyJrT0Mm
|
||||
snmp.contact=Verona Networks
|
||||
snmp.location=vntx
|
||||
snmp.status=enabled
|
||||
sshd.auth.passwd=enabled
|
||||
sshd.hostkey_dss=disabled
|
||||
sshd.port=22
|
||||
sshd.status=enabled
|
||||
syslog.remote.port=514
|
||||
syslog.remote.status=disabled
|
||||
syslog.status=enabled
|
||||
system.airosx.prov.status=enabled
|
||||
system.autosend_crash_reports=disabled
|
||||
system.cfg.editor.webui=2026-07-06T16:34:39.082Z
|
||||
system.cfg.version=65547
|
||||
system.date.status=disabled
|
||||
system.external.reset=enabled
|
||||
system.height=0
|
||||
system.latitude=33.1801
|
||||
system.leds.nightmode=disabled
|
||||
system.longitude=-96.498
|
||||
system.poe_passthrough=disabled
|
||||
system.timezone=CST6CDT,M3.2.0,M11.1.0
|
||||
system.timezone.name=America/Chicago
|
||||
telnetd.port=23
|
||||
telnetd.status=disabled
|
||||
tshaper.status=disabled
|
||||
unms.status=enabled
|
||||
unms.ui_url=https://uisp.vntx.net
|
||||
unms.uri=wss://uisp.vntx.net:443+xz9wxAnRIoFBZ30L4DUMQPPezD08hN-CXuge7VFMaIkAAAAA+allowUntrustedCertificate
|
||||
update.check.status=enabled
|
||||
users.status=enabled
|
||||
users.1.name=ubnt
|
||||
users.1.password=$1$CbZ01ZTh$yxjG1yPTbJ7wBlbif5hEC0
|
||||
users.1.status=enabled
|
||||
users.2.gid=100
|
||||
users.2.shell=/bin/false
|
||||
users.2.status=disabled
|
||||
users.2.uid=100
|
||||
wireless.status=enabled
|
||||
wireless.1.ampdu.frames=32
|
||||
wireless.1.ampdu.status=enabled
|
||||
wireless.1.amsdu=3
|
||||
wireless.1.devname=ath0
|
||||
wireless.1.hide_ssid=disabled
|
||||
wireless.1.l2_isolation=disabled
|
||||
wireless.1.mac_acl.policy=allow
|
||||
wireless.1.mac_acl.status=disabled
|
||||
wireless.1.mcast.enhance=0
|
||||
wireless.1.rate.auto=enabled
|
||||
wireless.1.rate.mcs=-1
|
||||
wireless.1.security.type=none
|
||||
wireless.1.signal_led_status=enabled
|
||||
wireless.1.signal_led1=94
|
||||
wireless.1.signal_led2=80
|
||||
wireless.1.signal_led3=73
|
||||
wireless.1.signal_led4=65
|
||||
wireless.1.ssid=vntx_pr_494
|
||||
wireless.1.status=enabled
|
||||
wireless.1.wds.status=enabled
|
||||
wpasupplicant.device.1.devname=ath0
|
||||
wpasupplicant.device.1.profile=AUTO
|
||||
wpasupplicant.device.1.status=disabled
|
||||
wpasupplicant.profile.1.name=AUTO
|
||||
wpasupplicant.profile.1.network.1.key_mgmt.1.name=WPA-PSK
|
||||
wpasupplicant.profile.1.network.1.pairwise.1.name=CCMP
|
||||
wpasupplicant.profile.1.network.1.proto.1.name=RSN
|
||||
wpasupplicant.profile.1.network.1.psk=0000:0000
|
||||
wpasupplicant.profile.1.network.1.ssid=vntx_pr_494
|
||||
wpasupplicant.profile.1.network.1.status=enabled
|
||||
wpasupplicant.profile.1.network.2.key_mgmt.1.name=NONE
|
||||
wpasupplicant.profile.1.network.2.priority=2
|
||||
wpasupplicant.profile.1.network.2.status=disabled
|
||||
wpasupplicant.status=disabled
|
||||
108
cpes.txt
Normal file
108
cpes.txt
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
## ePMP Force 110 (1 devices)
|
||||
00:04:56:F0:36:0F #125 Eddie Yarbrough 10.10.16.51
|
||||
|
||||
## ePMP Force 180 (36 devices)
|
||||
00:04:56:2E:B9:2E #185 Joanna Rodriguez 10.10.160.16
|
||||
00:04:56:2F:D7:CC #2098 Stephen Beegle 10.10.160.2
|
||||
00:04:56:2E:C9:FF #1829 Ashley Smith 10.10.160.6
|
||||
58:C1:7A:AD:14:9A #357 Brian Swedlund 10.10.160.7
|
||||
58:C1:7A:AC:65:08 #2200 Jennifer Boon 10.10.16.38
|
||||
00:04:56:44:5E:7B #343 Tim Bagert 10.10.16.40
|
||||
58:C1:7A:AD:22:EC #1650 luis Cabrera 10.10.64.1
|
||||
58:C1:7A:AC:64:51 #2454 Nancy Avellaneda 10.10.64.5
|
||||
58:C1:7A:AC:62:5F #2206 Wanda Davis 10.10.96.102
|
||||
00:04:56:2F:DB:A1 #355 Treceda Schmid 10.10.96.11
|
||||
58:C1:7A:AC:69:46 #2190 Ray Schaak 10.10.96.17
|
||||
00:04:56:2E:C1:6E #177 JERRY L JOHNSON 10.10.96.2
|
||||
00:04:56:2F:D4:BD #283 Paul Sammataro 10.10.96.29
|
||||
00:04:56:2F:CE:8D #2375 Yolanda Judge 10.10.96.35
|
||||
00:04:56:2F:DA:84 #1908 Gabriela Sereno 10.10.96.39
|
||||
58:C1:7A:AD:17:85 #2043 Angelica Cuayahuitl 10.10.96.45
|
||||
58:C1:7A:AC:63:19 #215 Kileigh Even 10.10.96.46
|
||||
58:C1:7A:AC:5F:11 #1538 Shirley Elmore 10.10.96.5
|
||||
00:04:56:2E:B7:6C #1316 Iris Delira 10.10.96.51
|
||||
00:04:56:44:54:0A #2046 HEATHER WOMACK 10.10.96.54
|
||||
00:04:56:44:50:AA #2023 Billy Horton 10.10.96.55
|
||||
58:C1:7A:B0:B6:1F #1128 Patricia Vasquez 10.10.96.58
|
||||
00:04:56:2F:DC:4C #10040 Thomas Graham 10.10.144.10
|
||||
58:C1:7A:AC:6A:C3 #10059 Nicholas Terry 10.10.144.11
|
||||
00:04:56:2F:CD:C7 #84 Coy Ungemach 10.10.144.2
|
||||
58:C1:7A:AD:15:7B #1906 Georgina Covarrubias 10.10.144.6
|
||||
58:C1:7A:AD:1F:20 #246 Matt Budjenska 10.10.158.247
|
||||
58:C1:7A:B0:B7:AE #1950 Leandra Beshea 10.10.128.1
|
||||
00:04:56:2F:D9:10 #1971 Clifford Jennings 10.10.128.11
|
||||
58:C1:7A:AD:13:D7 #100 Dave Kiowski 10.10.128.14
|
||||
00:04:56:44:5A:37 #997 Heather Brister 10.10.128.25
|
||||
00:04:56:44:52:ED #318 Shannon Brown 10.10.128.32
|
||||
00:04:56:44:50:68 #1949 RICHARD CONKLIN 10.10.128.34
|
||||
58:C1:7A:AC:5A:E5 #2489 Martha Flores 10.10.128.35
|
||||
58:C1:7A:AC:E8:81 #2492 Kory Biggs Shop 10.10.128.43
|
||||
00:04:56:2F:DA:E7 #2010 Brady Clayton 10.10.128.48
|
||||
|
||||
## ePMP Force 200 (59 devices)
|
||||
00:04:56:DC:69:AE #932 Matt Kosarek 10.10.160.19
|
||||
00:04:56:DB:D2:CA #1168 Stephen Day 10.10.160.22
|
||||
00:04:56:DB:EC:11 #2037 Kevin Arana 10.10.160.9
|
||||
00:04:56:DB:63:5E #2410 Carol Strickland 10.10.16.37
|
||||
00:04:56:4A:12:EE #2133 Glenda Beauchamp 10.10.16.41
|
||||
58:C1:7A:B1:05:12 #2275 John Vayo 10.10.16.47
|
||||
58:C1:7A:B0:D7:10 #2233 Crystal Harney 10.10.16.50
|
||||
00:04:56:DB:57:2B #855 Amber Prater 10.10.16.56
|
||||
58:C1:7A:B1:09:F8 #2360 Doug Garber 10.10.16.57
|
||||
00:04:56:DC:73:98 #2530 Donna Campbell 10.10.16.58
|
||||
58:C1:7A:B3:07:A1 #435 Maria Cortes 10.10.64.12
|
||||
00:04:56:DB:EB:18 #490 Terry Bates 10.10.64.8
|
||||
58:C1:7A:B1:02:63 #192 Aurea Sanchez 10.10.96.10
|
||||
00:04:56:DB:99:40 #2407 David Roesch 10.10.96.13
|
||||
00:04:56:48:63:EF #587 Tamy Thomas 10.10.96.14
|
||||
00:04:56:DB:C2:2C #497 Jody McCluskey 10.10.96.26
|
||||
00:04:56:DB:EA:A0 #2487 Anthony Longo 10.10.96.33
|
||||
00:04:56:4A:17:53 #10074 Pablo Martinez 10.10.96.36
|
||||
00:04:56:DB:E9:FE #2479 Thomas Hernandez 10.10.96.38
|
||||
00:04:56:DB:E5:ED #1788 Tim Bronschidle 10.10.96.40
|
||||
58:C1:7A:B0:F3:39 #2335 Tiffany Stewart 10.10.96.42
|
||||
00:04:56:DC:73:6B #10027 Irene Garibay 10.10.96.50
|
||||
00:04:56:DC:6B:55 #10052 Khushboo Agarwal 10.10.96.53
|
||||
58:C1:7A:B0:D7:0D #1601 Jerid Rutledge 10.10.96.65
|
||||
00:04:56:DC:6C:9F #293 Jeff Harder 10.10.96.67
|
||||
58:C1:7A:B3:06:A8 #875 Ken Patrick 10.10.96.7
|
||||
00:04:56:DC:67:59 #1467 Terri Mack 10.10.96.72
|
||||
00:04:56:DC:59:A6 #427 Ausencio Luna 10.10.96.73
|
||||
00:04:56:DB:C2:11 #433 Balnca Diaz 10.10.96.77
|
||||
00:04:56:DC:6D:77 #1712 Bobby Mack 10.10.96.84
|
||||
00:04:56:48:66:E3 #10024 Janis Stewart 10.10.96.9
|
||||
00:04:56:4A:15:B5 #10073 Jeffrey Harder 10.10.96.95
|
||||
00:04:56:4A:13:7E #1441 Doris Avalos 10.10.144.16
|
||||
58:C1:7A:B0:F7:8F #224 Leonard Lewis 10.10.144.20
|
||||
00:04:56:DC:79:38 #477 Helen Lumpkin 10.10.144.24
|
||||
00:04:56:DC:72:2A #735 FRED HECKEL 10.10.144.25
|
||||
00:04:56:DB:E8:D5 #990 Jennifer Dunaway 10.10.144.27
|
||||
00:04:56:DC:6A:65 #345 Tim Fisher 10.10.144.31
|
||||
00:04:56:DB:AA:E6 #815 Terry Gortney 10.10.144.32
|
||||
00:04:56:DC:5D:63 #243 Mark Nunnelee 10.10.144.35
|
||||
00:04:56:DC:60:8D #1081 Abbie Andrews 10.10.144.36
|
||||
00:04:56:DC:04:EF #301 Ron Berger 10.10.144.4
|
||||
00:04:56:DC:72:24 #339 Terry Miesen 10.10.144.7
|
||||
00:04:56:DB:97:F9 #848 Douglas Wilson 10.10.128.13
|
||||
00:04:56:4A:17:B3 #2027 Chris Clayton 10.10.128.18
|
||||
00:04:56:DC:69:F0 #2458 Marcus Patton 10.10.128.28
|
||||
00:04:56:DB:E7:4C #46 Bernard Heer 10.10.128.3
|
||||
00:04:56:DC:5E:50 #2465 Kory Biggs 10.10.128.33
|
||||
00:04:56:DC:06:B7 #568 Frances Kirby 10.10.128.37
|
||||
00:04:56:DC:05:04 #556 Mike Bell 10.10.128.45
|
||||
58:C1:7A:B0:D0:20 #997 Heather Brister 10.10.128.50
|
||||
00:04:56:DC:71:E8 #1879 Chris Telles 10.10.128.51
|
||||
00:04:56:DC:6A:0B #1585 Tim Thomas 10.10.128.52
|
||||
00:04:56:DC:66:06 #146 Geok Choon Pang 10.10.128.54
|
||||
58:C1:7A:B0:F8:49 #2280 Ken Hall 10.10.128.6
|
||||
58:C1:7A:B1:04:8B #2292 Joe Speciale 10.10.128.63
|
||||
00:04:56:DB:EB:78 #809 Brad Gurney 10.10.128.8
|
||||
58:C1:7A:B0:C1:3B #2295 Christine Hamparyan 10.10.142.252
|
||||
58:C1:7A:B1:05:D2 #2218 Greg Hummel 10.10.142.253
|
||||
|
||||
## no response (1 devices)
|
||||
58:C1:7A:B3:08:B8 #623 Michael Newby 10.10.96.91
|
||||
|
||||
## Ubiquiti (unknown model) (1 devices)
|
||||
E0:63:DA:0F:B8:F5 #2529 Terry Rector 10.10.62.208
|
||||
97
cpes_annotated.txt
Normal file
97
cpes_annotated.txt
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
MAC Model Account IP
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
00:04:56:DC:60:8D PowerBeam M5 / Loco M5 | fw=5.10.4 #1081 Abbie Andrews 10.10.144.36
|
||||
00:04:56:DB:57:2B PowerBeam M5 / Loco M5 | fw=5.11.0 #855 Amber Prater 10.10.16.56
|
||||
58:C1:7A:AD:17:85 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #2043 Angelica Cuayahuitl 10.10.96.45
|
||||
00:04:56:DB:EA:A0 PowerBeam M5 / Loco M5 | fw=5.10.4 #2487 Anthony Longo 10.10.96.33
|
||||
00:04:56:2E:C9:FF NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #1829 Ashley Smith 10.10.160.6
|
||||
58:C1:7A:B1:02:63 PowerBeam M5 / Loco M5 | fw=5.10.4 #192 Aurea Sanchez 10.10.96.10
|
||||
00:04:56:DC:59:A6 PowerBeam M5 / Loco M5 | fw=5.10.4 #427 Ausencio Luna 10.10.96.73
|
||||
00:04:56:DB:C2:11 PowerBeam M5 / Loco M5 | fw=5.11.1 #433 Balnca Diaz 10.10.96.77
|
||||
00:04:56:DB:E7:4C PowerBeam M5 / Loco M5 | fw=5.11.0 #46 Bernard Heer 10.10.128.3
|
||||
00:04:56:44:50:AA NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #2023 Billy Horton 10.10.96.55
|
||||
00:04:56:DC:6D:77 PowerBeam M5 / Loco M5 | fw=5.10.4 #1712 Bobby Mack 10.10.96.84
|
||||
00:04:56:DB:EB:78 PowerBeam M5 / Loco M5 | fw=5.11.0 #809 Brad Gurney 10.10.128.8
|
||||
00:04:56:2F:DA:E7 NanoBeam M5 / LiteBeam M5 | fw=5.11.0 #2010 Brady Clayton 10.10.128.48
|
||||
58:C1:7A:AD:14:9A NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #357 Brian Swedlund 10.10.160.7
|
||||
00:04:56:DB:63:5E PowerBeam M5 / Loco M5 | fw=5.11.1 #2410 Carol Strickland 10.10.16.37
|
||||
00:04:56:4A:17:B3 PowerBeam M5 / Loco M5 | fw=5.11.1 #2027 Chris Clayton 10.10.128.18
|
||||
00:04:56:DC:71:E8 PowerBeam M5 / Loco M5 | fw=5.11.1 #1879 Chris Telles 10.10.128.51
|
||||
58:C1:7A:B0:C1:3B PowerBeam M5 / Loco M5 | fw=5.10.4 #2295 Christine Hamparyan 10.10.142.252
|
||||
00:04:56:2F:D9:10 NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #1971 Clifford Jennings 10.10.128.11
|
||||
00:04:56:2F:CD:C7 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #84 Coy Ungemach 10.10.144.2
|
||||
58:C1:7A:B0:D7:10 PowerBeam M5 / Loco M5 | fw=5.11.0 #2233 Crystal Harney 10.10.16.50
|
||||
58:C1:7A:AD:13:D7 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #100 Dave Kiowski 10.10.128.14
|
||||
00:04:56:DB:99:40 PowerBeam M5 / Loco M5 | fw=5.10.4 #2407 David Roesch 10.10.96.13
|
||||
00:04:56:DC:73:98 PowerBeam M5 / Loco M5 | fw=5.11.0 #2530 Donna Campbell 10.10.16.58
|
||||
00:04:56:4A:13:7E PowerBeam M5 / Loco M5 | fw=5.10.4 #1441 Doris Avalos 10.10.144.16
|
||||
58:C1:7A:B1:09:F8 PowerBeam M5 / Loco M5 | fw=5.11.1 #2360 Doug Garber 10.10.16.57
|
||||
00:04:56:DB:97:F9 PowerBeam M5 / Loco M5 | fw=5.11.1 #848 Douglas Wilson 10.10.128.13
|
||||
00:04:56:DC:06:B7 PowerBeam M5 / Loco M5 | fw=5.11.1 #568 Frances Kirby 10.10.128.37
|
||||
00:04:56:DC:72:2A PowerBeam M5 / Loco M5 | fw=5.10.4 #735 FRED HECKEL 10.10.144.25
|
||||
00:04:56:2F:DA:84 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #1908 Gabriela Sereno 10.10.96.39
|
||||
00:04:56:DC:66:06 PowerBeam M5 / Loco M5 | fw=5.11.1 #146 Geok Choon Pang 10.10.128.54
|
||||
58:C1:7A:AD:15:7B NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #1906 Georgina Covarrubias 10.10.144.6
|
||||
00:04:56:4A:12:EE PowerBeam M5 / Loco M5 | fw=5.11.0 #2133 Glenda Beauchamp 10.10.16.41
|
||||
58:C1:7A:B1:05:D2 PowerBeam M5 / Loco M5 | fw=5.10.4 #2218 Greg Hummel 10.10.142.253
|
||||
00:04:56:44:5A:37 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #997 Heather Brister 10.10.128.25
|
||||
58:C1:7A:B0:D0:20 PowerBeam M5 / Loco M5 | fw=5.10.4 #997 Heather Brister 10.10.128.50
|
||||
00:04:56:44:54:0A NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #2046 HEATHER WOMACK 10.10.96.54
|
||||
00:04:56:DC:79:38 PowerBeam M5 / Loco M5 | fw=5.10.4 #477 Helen Lumpkin 10.10.144.24
|
||||
00:04:56:DC:73:6B PowerBeam M5 / Loco M5 | fw=4.8.1 #10027 Irene Garibay 10.10.96.50
|
||||
00:04:56:2E:B7:6C NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #1316 Iris Delira 10.10.96.51
|
||||
00:04:56:48:66:E3 PowerBeam M5 / Loco M5 | fw=5.10.4 #10024 Janis Stewart 10.10.96.9
|
||||
00:04:56:DC:6C:9F PowerBeam M5 / Loco M5 | fw=5.10.4 #293 Jeff Harder 10.10.96.67
|
||||
00:04:56:4A:15:B5 PowerBeam M5 / Loco M5 | fw=5.10.4 #10073 Jeffrey Harder 10.10.96.95
|
||||
58:C1:7A:AC:65:08 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #2200 Jennifer Boon 10.10.16.38
|
||||
00:04:56:DB:E8:D5 PowerBeam M5 / Loco M5 | fw=5.10.4 #990 Jennifer Dunaway 10.10.144.27
|
||||
58:C1:7A:B0:D7:0D PowerBeam M5 / Loco M5 | fw=5.10.4 #1601 Jerid Rutledge 10.10.96.65
|
||||
00:04:56:2E:C1:6E NanoBeam M5 / LiteBeam M5 | fw=5.11.0 #177 JERRY L JOHNSON 10.10.96.2
|
||||
00:04:56:2E:B9:2E NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #185 Joanna Rodriguez 10.10.160.16
|
||||
00:04:56:DB:C2:2C PowerBeam M5 / Loco M5 | fw=5.10.4 #497 Jody McCluskey 10.10.96.26
|
||||
58:C1:7A:B1:04:8B PowerBeam M5 / Loco M5 | fw=5.11.0 #2292 Joe Speciale 10.10.128.63
|
||||
58:C1:7A:B1:05:12 PowerBeam M5 / Loco M5 | fw=5.11.0 #2275 John Vayo 10.10.16.47
|
||||
58:C1:7A:B0:F8:49 PowerBeam M5 / Loco M5 | fw=5.11.0 #2280 Ken Hall 10.10.128.6
|
||||
58:C1:7A:B3:06:A8 PowerBeam M5 / Loco M5 | fw=5.11.1 #875 Ken Patrick 10.10.96.7
|
||||
00:04:56:DB:EC:11 PowerBeam M5 / Loco M5 | fw=5.11.1 #2037 Kevin Arana 10.10.160.9
|
||||
00:04:56:DC:6B:55 PowerBeam M5 / Loco M5 | fw=5.10.4 #10052 Khushboo Agarwal 10.10.96.53
|
||||
58:C1:7A:AC:63:19 NanoBeam M5 / LiteBeam M5 | fw=4.6.0.1 #215 Kileigh Even 10.10.96.46
|
||||
00:04:56:DC:5E:50 PowerBeam M5 / Loco M5 | fw=5.11.1 #2465 Kory Biggs 10.10.128.33
|
||||
58:C1:7A:AC:E8:81 NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #2492 Kory Biggs Shop 10.10.128.43
|
||||
58:C1:7A:B0:B7:AE NanoBeam M5 / LiteBeam M5 | fw=5.11.0 #1950 Leandra Beshea 10.10.128.1
|
||||
58:C1:7A:B0:F7:8F PowerBeam M5 / Loco M5 | fw=5.10.4 #224 Leonard Lewis 10.10.144.20
|
||||
58:C1:7A:AD:22:EC NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #1650 luis Cabrera 10.10.64.1
|
||||
00:04:56:DC:69:F0 PowerBeam M5 / Loco M5 | fw=5.11.1 #2458 Marcus Patton 10.10.128.28
|
||||
58:C1:7A:B3:07:A1 PowerBeam M5 / Loco M5 | fw=5.11.1 #435 Maria Cortes 10.10.64.12
|
||||
00:04:56:DC:5D:63 PowerBeam M5 / Loco M5 | fw=5.10.4 #243 Mark Nunnelee 10.10.144.35
|
||||
58:C1:7A:AC:5A:E5 NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #2489 Martha Flores 10.10.128.35
|
||||
58:C1:7A:AD:1F:20 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #246 Matt Budjenska 10.10.158.247
|
||||
00:04:56:DC:69:AE PowerBeam M5 / Loco M5 | fw=5.11.1 #932 Matt Kosarek 10.10.160.19
|
||||
58:C1:7A:B3:08:B8 PowerBeam M5 / Loco M5 | fw=5.10.4 #623 Michael Newby 10.10.96.91
|
||||
00:04:56:DC:05:04 PowerBeam M5 / Loco M5 | fw=5.11.1 #556 Mike Bell 10.10.128.45
|
||||
58:C1:7A:AC:64:51 NanoBeam M5 / LiteBeam M5 | fw=4.7 #2454 Nancy Avellaneda 10.10.64.5
|
||||
58:C1:7A:AC:6A:C3 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #10059 Nicholas Terry 10.10.144.11
|
||||
00:04:56:4A:17:53 PowerBeam M5 / Loco M5 | fw=5.10.4 #10074 Pablo Martinez 10.10.96.36
|
||||
58:C1:7A:B0:B6:1F NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #1128 Patricia Vasquez 10.10.96.58
|
||||
00:04:56:2F:D4:BD NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #283 Paul Sammataro 10.10.96.29
|
||||
58:C1:7A:AC:69:46 NanoBeam M5 / LiteBeam M5 | fw=4.7 #2190 Ray Schaak 10.10.96.17
|
||||
00:04:56:44:50:68 NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #1949 RICHARD CONKLIN 10.10.128.34
|
||||
00:04:56:DC:04:EF PowerBeam M5 / Loco M5 | fw=5.10.4 #301 Ron Berger 10.10.144.4
|
||||
00:04:56:44:52:ED NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #318 Shannon Brown 10.10.128.32
|
||||
58:C1:7A:AC:5F:11 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #1538 Shirley Elmore 10.10.96.5
|
||||
00:04:56:2F:D7:CC NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #2098 Stephen Beegle 10.10.160.2
|
||||
00:04:56:DB:D2:CA PowerBeam M5 / Loco M5 | fw=5.11.1 #1168 Stephen Day 10.10.160.22
|
||||
00:04:56:48:63:EF PowerBeam M5 / Loco M5 | fw=4.7.0.1 #587 Tamy Thomas 10.10.96.14
|
||||
00:04:56:DC:67:59 PowerBeam M5 / Loco M5 | fw=5.10.4 #1467 Terri Mack 10.10.96.72
|
||||
00:04:56:DB:EB:18 PowerBeam M5 / Loco M5 | fw=5.11.1 #490 Terry Bates 10.10.64.8
|
||||
00:04:56:DB:AA:E6 PowerBeam M5 / Loco M5 | fw=5.10.4 #815 Terry Gortney 10.10.144.32
|
||||
00:04:56:DC:72:24 PowerBeam M5 / Loco M5 | fw=5.10.4 #339 Terry Miesen 10.10.144.7
|
||||
00:04:56:2F:DC:4C NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #10040 Thomas Graham 10.10.144.10
|
||||
00:04:56:DB:E9:FE PowerBeam M5 / Loco M5 | fw=5.10.4 #2479 Thomas Hernandez 10.10.96.38
|
||||
58:C1:7A:B0:F3:39 PowerBeam M5 / Loco M5 | fw=5.10.4 #2335 Tiffany Stewart 10.10.96.42
|
||||
00:04:56:DC:6A:0B PowerBeam M5 / Loco M5 | fw=4.8.1 #1585 Tim Thomas 10.10.128.52
|
||||
00:04:56:44:5E:7B NanoBeam M5 / LiteBeam M5 | fw=5.11.1 #343 Tim Bagert 10.10.16.40
|
||||
00:04:56:DB:E5:ED PowerBeam M5 / Loco M5 | fw=5.10.4 #1788 Tim Bronschidle 10.10.96.40
|
||||
00:04:56:DC:6A:65 PowerBeam M5 / Loco M5 | fw=5.10.4 #345 Tim Fisher 10.10.144.31
|
||||
00:04:56:2F:DB:A1 NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #355 Treceda Schmid 10.10.96.11
|
||||
00:04:56:2F:CE:8D NanoBeam M5 / LiteBeam M5 | fw=5.10.4 #2375 Yolanda Judge 10.10.96.35
|
||||
119
cpes_by_model.txt
Normal file
119
cpes_by_model.txt
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
Identifying 91 devices via HTTPS...
|
||||
20/91
|
||||
40/91
|
||||
60/91
|
||||
80/91
|
||||
91/91 done
|
||||
|
||||
## Cambium ePMP (unknown model) (1 devices)
|
||||
58:C1:7A:B3:08:B8 #623 Michael Newby 10.10.96.91
|
||||
|
||||
## ePMP Force 110 (fw=Version 5.11.1) (1 devices)
|
||||
00:04:56:F0:36:0F #125 Eddie Yarbrough 10.10.16.51
|
||||
|
||||
## ePMP Force 180 (fw=Version 5.10.4) (17 devices)
|
||||
58:C1:7A:AD:17:85 #2043 Angelica Cuayahuitl 10.10.96.45
|
||||
00:04:56:44:50:AA #2023 Billy Horton 10.10.96.55
|
||||
00:04:56:2F:CD:C7 #84 Coy Ungemach 10.10.144.2
|
||||
58:C1:7A:AD:13:D7 #100 Dave Kiowski 10.10.128.14
|
||||
00:04:56:2F:DA:84 #1908 Gabriela Sereno 10.10.96.39
|
||||
58:C1:7A:AD:15:7B #1906 Georgina Covarrubias 10.10.144.6
|
||||
00:04:56:44:5A:37 #997 Heather Brister 10.10.128.25
|
||||
00:04:56:2E:B7:6C #1316 Iris Delira 10.10.96.51
|
||||
58:C1:7A:AC:65:08 #2200 Jennifer Boon 10.10.16.38
|
||||
00:04:56:2E:B9:2E #185 Joanna Rodriguez 10.10.160.16
|
||||
58:C1:7A:AD:1F:20 #246 Matt Budjenska 10.10.158.247
|
||||
58:C1:7A:B0:B6:1F #1128 Patricia Vasquez 10.10.96.58
|
||||
00:04:56:2F:D4:BD #283 Paul Sammataro 10.10.96.29
|
||||
58:C1:7A:AC:5F:11 #1538 Shirley Elmore 10.10.96.5
|
||||
00:04:56:2F:D7:CC #2098 Stephen Beegle 10.10.160.2
|
||||
00:04:56:2F:DB:A1 #355 Treceda Schmid 10.10.96.11
|
||||
00:04:56:2F:CE:8D #2375 Yolanda Judge 10.10.96.35
|
||||
|
||||
## ePMP Force 180 (fw=Version 5.11.0) (3 devices)
|
||||
00:04:56:2F:DA:E7 #2010 Brady Clayton 10.10.128.48
|
||||
00:04:56:2E:C1:6E #177 JERRY L JOHNSON 10.10.96.2
|
||||
58:C1:7A:B0:B7:AE #1950 Leandra Beshea 10.10.128.1
|
||||
|
||||
## ePMP Force 180 (fw=Version 5.11.1) (10 devices)
|
||||
00:04:56:2E:C9:FF #1829 Ashley Smith 10.10.160.6
|
||||
58:C1:7A:AD:14:9A #357 Brian Swedlund 10.10.160.7
|
||||
00:04:56:2F:D9:10 #1971 Clifford Jennings 10.10.128.11
|
||||
00:04:56:44:54:0A #2046 HEATHER WOMACK 10.10.96.54
|
||||
58:C1:7A:AC:E8:81 #2492 Kory Biggs Shop 10.10.128.43
|
||||
58:C1:7A:AD:22:EC #1650 luis Cabrera 10.10.64.1
|
||||
58:C1:7A:AC:5A:E5 #2489 Martha Flores 10.10.128.35
|
||||
00:04:56:44:50:68 #1949 RICHARD CONKLIN 10.10.128.34
|
||||
00:04:56:44:52:ED #318 Shannon Brown 10.10.128.32
|
||||
00:04:56:44:5E:7B #343 Tim Bagert 10.10.16.40
|
||||
|
||||
## ePMP Force 200 (fw=Version 4.8.1) (1 devices)
|
||||
00:04:56:DC:6A:0B #1585 Tim 10.10.128.52
|
||||
|
||||
## ePMP Force 200 (fw=Version 5.10.4) (26 devices)
|
||||
00:04:56:DC:60:8D #1081 Abbie Andrews 10.10.144.36
|
||||
00:04:56:DB:EA:A0 #2487 Anthony Longo 10.10.96.33
|
||||
58:C1:7A:B1:02:63 #192 Aurea Sanchez 10.10.96.10
|
||||
00:04:56:DC:59:A6 #427 Ausencio Luna 10.10.96.73
|
||||
00:04:56:DC:6D:77 #1712 Bobby Mack 10.10.96.84
|
||||
58:C1:7A:B0:C1:3B #2295 Christine Hamparyan 10.10.142.252
|
||||
00:04:56:DB:99:40 #2407 David Roesch 10.10.96.13
|
||||
00:04:56:4A:13:7E #1441 Doris Avalos 10.10.144.16
|
||||
00:04:56:DC:72:2A #735 FRED HECKEL 10.10.144.25
|
||||
58:C1:7A:B1:05:D2 #2218 Greg Hummel 10.10.142.253
|
||||
58:C1:7A:B0:D0:20 #997 Heather Brister 10.10.128.50
|
||||
00:04:56:DC:79:38 #477 Helen Lumpkin 10.10.144.24
|
||||
00:04:56:DC:6C:9F #293 Jeff Harder 10.10.96.67
|
||||
00:04:56:DB:E8:D5 #990 Jennifer Dunaway 10.10.144.27
|
||||
58:C1:7A:B0:D7:0D #1601 Jerid Rutledge 10.10.96.65
|
||||
00:04:56:DB:C2:2C #497 Jody McCluskey 10.10.96.26
|
||||
58:C1:7A:B0:F7:8F #224 Leonard Lewis 10.10.144.20
|
||||
00:04:56:DC:5D:63 #243 Mark Nunnelee 10.10.144.35
|
||||
00:04:56:DC:04:EF #301 Ron Berger 10.10.144.4
|
||||
00:04:56:DC:67:59 #1467 Terri Mack 10.10.96.72
|
||||
00:04:56:DB:AA:E6 #815 Terry Gortney 10.10.144.32
|
||||
00:04:56:DC:72:24 #339 Terry Miesen 10.10.144.7
|
||||
00:04:56:DB:E9:FE #2479 Thomas Hernandez 10.10.96.38
|
||||
58:C1:7A:B0:F3:39 #2335 Tiffany Stewart 10.10.96.42
|
||||
00:04:56:DB:E5:ED #1788 Tim Bronschidle 10.10.96.40
|
||||
00:04:56:DC:6A:65 #345 Tim Fisher 10.10.144.31
|
||||
|
||||
## ePMP Force 200 (fw=Version 5.11.0) (9 devices)
|
||||
00:04:56:DB:57:2B #855 Amber Prater 10.10.16.56
|
||||
00:04:56:DB:E7:4C #46 Bernard Heer 10.10.128.3
|
||||
00:04:56:DB:EB:78 #809 Brad Gurney 10.10.128.8
|
||||
58:C1:7A:B0:D7:10 #2233 Crystal Harney 10.10.16.50
|
||||
00:04:56:DC:73:98 #2530 Donna Campbell 10.10.16.58
|
||||
00:04:56:4A:12:EE #2133 Glenda Beauchamp 10.10.16.41
|
||||
58:C1:7A:B1:04:8B #2292 Joe Speciale 10.10.128.63
|
||||
58:C1:7A:B1:05:12 #2275 John Vayo 10.10.16.47
|
||||
58:C1:7A:B0:F8:49 #2280 Ken Hall 10.10.128.6
|
||||
|
||||
## ePMP Force 200 (fw=Version 5.11.1) (17 devices)
|
||||
00:04:56:DB:C2:11 #433 Balnca Diaz 10.10.96.77
|
||||
00:04:56:DB:63:5E #2410 Carol Strickland 10.10.16.37
|
||||
00:04:56:4A:17:B3 #2027 Chris Clayton 10.10.128.18
|
||||
00:04:56:DC:71:E8 #1879 Chris Telles 10.10.128.51
|
||||
58:C1:7A:B1:09:F8 #2360 Doug Garber 10.10.16.57
|
||||
00:04:56:DB:97:F9 #848 Douglas Wilson 10.10.128.13
|
||||
00:04:56:DC:06:B7 #568 Frances Kirby 10.10.128.37
|
||||
00:04:56:DC:66:06 #146 Geok Choon Pang 10.10.128.54
|
||||
58:C1:7A:B3:06:A8 #875 Ken Patrick 10.10.96.7
|
||||
00:04:56:DB:EC:11 #2037 Kevin Arana 10.10.160.9
|
||||
00:04:56:DC:5E:50 #2465 Kory Biggs 10.10.128.33
|
||||
00:04:56:DC:69:F0 #2458 Marcus Patton 10.10.128.28
|
||||
58:C1:7A:B3:07:A1 #435 Maria Cortes 10.10.64.12
|
||||
00:04:56:DC:69:AE #932 Matt Kosarek 10.10.160.19
|
||||
00:04:56:DC:05:04 #556 Mike Bell 10.10.128.45
|
||||
00:04:56:DB:D2:CA #1168 Stephen Day 10.10.160.22
|
||||
00:04:56:DB:EB:18 #490 Terry Bates 10.10.64.8
|
||||
|
||||
## no HTTPS response (5 devices)
|
||||
58:C1:7A:AC:63:19 #215 Kileigh Even 10.10.96.46
|
||||
58:C1:7A:AC:64:51 #2454 Nancy Avellaneda 10.10.64.5
|
||||
58:C1:7A:AC:69:46 #2190 Ray Schaak 10.10.96.17
|
||||
58:C1:7A:AC:62:5F #2206 Wanda Davis 10.10.96.102
|
||||
00:04:56:48:63:EF #587 Tamy Thomas 10.10.96.14
|
||||
|
||||
## Ubiquiti (unknown model) (1 devices)
|
||||
E0:63:DA:0F:B8:F5 #2529 Terry Rector 10.10.62.208
|
||||
196
cpes_raw.txt
Normal file
196
cpes_raw.txt
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
router=494 ip=10.10.160.16 mac=00:04:56:2E:B9:2E device=Ubiquiti (legacy)
|
||||
account=#185 name='Joanna Rodriguez' host='Joanna Rodriguez'
|
||||
router=494 ip=10.10.160.19 mac=00:04:56:DC:69:AE device=Ubiquiti (legacy)
|
||||
account=#932 name='Matt Kosarek' host='Matt Kosarek'
|
||||
router=494 ip=10.10.160.2 mac=00:04:56:2F:D7:CC device=Ubiquiti (legacy)
|
||||
account=#2098 name='Stephen Beegle' host='Stephen Beegle'
|
||||
router=494 ip=10.10.160.22 mac=00:04:56:DB:D2:CA device=Ubiquiti (legacy)
|
||||
account=#1168 name='Stephen Day' host='Stephen Day'
|
||||
router=494 ip=10.10.160.6 mac=00:04:56:2E:C9:FF device=Ubiquiti (legacy)
|
||||
account=#1829 name='Ashley Smith' host='Ashley Smith'
|
||||
router=494 ip=10.10.160.7 mac=58:C1:7A:AD:14:9A device=Cambium ePMP
|
||||
account=#357 name='Brian Swedlund' host='Brian Swedlund'
|
||||
router=494 ip=10.10.160.9 mac=00:04:56:DB:EC:11 device=Ubiquiti (legacy)
|
||||
account=#2037 name='Kevin Arana' host='Kevin Arana'
|
||||
router=982 ip=10.10.62.208 mac=E0:63:DA:0F:B8:F5 device=Ubiquiti PowerBeam M5 / Loco M5
|
||||
account=#2529 name='Terry Rector' host='Terry-Rector'
|
||||
router=climax ip=10.10.16.37 mac=00:04:56:DB:63:5E device=Ubiquiti (legacy)
|
||||
account=#2410 name='Carol Strickland' host='Carol Strickland'
|
||||
router=climax ip=10.10.16.38 mac=58:C1:7A:AC:65:08 device=Cambium ePMP
|
||||
account=#2200 name='Jennifer Boon' host='Jennifer Boon'
|
||||
router=climax ip=10.10.16.40 mac=00:04:56:44:5E:7B device=Ubiquiti (legacy)
|
||||
account=#343 name='Tim Bagert' host='Tim Bagert'
|
||||
router=climax ip=10.10.16.41 mac=00:04:56:4A:12:EE device=Ubiquiti (legacy)
|
||||
account=#2133 name='Glenda Beauchamp' host='Glenda Beauchamp'
|
||||
router=climax ip=10.10.16.47 mac=58:C1:7A:B1:05:12 device=Cambium ePMP
|
||||
account=#2275 name='John Vayo' host='John Vayo'
|
||||
router=climax ip=10.10.16.50 mac=58:C1:7A:B0:D7:10 device=Cambium ePMP
|
||||
account=#2233 name='Crystal Harney' host='Crystal Harney'
|
||||
router=climax ip=10.10.16.51 mac=00:04:56:F0:36:0F device=Ubiquiti (legacy)
|
||||
account=#125 name='Eddie Yarbrough' host='Eddie Yarbrough'
|
||||
router=climax ip=10.10.16.56 mac=00:04:56:DB:57:2B device=Ubiquiti (legacy)
|
||||
account=#855 name='Amber Prater' host='Amber Prater'
|
||||
router=climax ip=10.10.16.57 mac=58:C1:7A:B1:09:F8 device=Cambium ePMP
|
||||
account=#2360 name='Doug Garber' host='Doug Garber'
|
||||
router=climax ip=10.10.16.58 mac=00:04:56:DC:73:98 device=Ubiquiti (legacy)
|
||||
account=#2530 name='Donna Campbell' host='Donna Campbell'
|
||||
router=core ip=10.10.64.1 mac=58:C1:7A:AD:22:EC device=Cambium ePMP
|
||||
account=#1650 name='luis Cabrera' host='Luis Cabrera'
|
||||
router=core ip=10.10.64.12 mac=58:C1:7A:B3:07:A1 device=Cambium ePMP
|
||||
account=#435 name='Maria Cortes' host='Maria Cortes'
|
||||
router=core ip=10.10.64.5 mac=58:C1:7A:AC:64:51 device=Cambium ePMP
|
||||
account=#2454 name='Nancy Avellaneda' host='Nancy Avellaneda'
|
||||
router=core ip=10.10.64.8 mac=00:04:56:DB:EB:18 device=Ubiquiti (legacy)
|
||||
account=#490 name='Terry Bates' host='Terry Bates'
|
||||
router=culleoka ip=10.10.96.10 mac=58:C1:7A:B1:02:63 device=Cambium ePMP
|
||||
account=#192 name='Aurea Sanchez' host='Aurea Sanchez'
|
||||
router=culleoka ip=10.10.96.102 mac=58:C1:7A:AC:62:5F device=Cambium ePMP
|
||||
account=#2206 name='Wanda Davis' host='Wanda Davis'
|
||||
router=culleoka ip=10.10.96.11 mac=00:04:56:2F:DB:A1 device=Ubiquiti (legacy)
|
||||
account=#355 name='Treceda Schmid' host='Treceda Schmid'
|
||||
router=culleoka ip=10.10.96.13 mac=00:04:56:DB:99:40 device=Ubiquiti (legacy)
|
||||
account=#2407 name='David Roesch' host='David Roesch'
|
||||
router=culleoka ip=10.10.96.14 mac=00:04:56:48:63:EF device=Ubiquiti (legacy)
|
||||
account=#587 name='Tamy Thomas' host='Tamy Thomas'
|
||||
router=culleoka ip=10.10.96.17 mac=58:C1:7A:AC:69:46 device=Cambium ePMP
|
||||
account=#2190 name='Ray Schaak' host='Ray Schaak'
|
||||
router=culleoka ip=10.10.96.2 mac=00:04:56:2E:C1:6E device=Ubiquiti (legacy)
|
||||
account=#177 name='JERRY L JOHNSON' host='Jerry Johnson'
|
||||
router=culleoka ip=10.10.96.26 mac=00:04:56:DB:C2:2C device=Ubiquiti (legacy)
|
||||
account=#497 name='Jody McCluskey' host='Jody McCluskey'
|
||||
router=culleoka ip=10.10.96.29 mac=00:04:56:2F:D4:BD device=Ubiquiti (legacy)
|
||||
account=#283 name='Paul Sammataro' host='Paul Sammataro'
|
||||
router=culleoka ip=10.10.96.33 mac=00:04:56:DB:EA:A0 device=Ubiquiti (legacy)
|
||||
account=#2487 name='Anthony Longo' host='Anthony Longo'
|
||||
router=culleoka ip=10.10.96.35 mac=00:04:56:2F:CE:8D device=Ubiquiti (legacy)
|
||||
account=#2375 name='Yolanda Judge' host='Yolanda Judge'
|
||||
router=culleoka ip=10.10.96.36 mac=00:04:56:4A:17:53 device=Ubiquiti (legacy)
|
||||
account=#10074 name='Pablo Martinez' host='Pablo Martinez'
|
||||
router=culleoka ip=10.10.96.38 mac=00:04:56:DB:E9:FE device=Ubiquiti (legacy)
|
||||
account=#2479 name='Thomas Hernandez' host='Thomas Hernandez'
|
||||
router=culleoka ip=10.10.96.39 mac=00:04:56:2F:DA:84 device=Ubiquiti (legacy)
|
||||
account=#1908 name='Gabriela Sereno' host='Gabriela Sereno'
|
||||
router=culleoka ip=10.10.96.40 mac=00:04:56:DB:E5:ED device=Ubiquiti (legacy)
|
||||
account=#1788 name='Tim Bronschidle' host='Tim Bronschidle'
|
||||
router=culleoka ip=10.10.96.42 mac=58:C1:7A:B0:F3:39 device=Cambium ePMP
|
||||
account=#2335 name='Tiffany Stewart' host='Tiffany Stewart'
|
||||
router=culleoka ip=10.10.96.45 mac=58:C1:7A:AD:17:85 device=Cambium ePMP
|
||||
account=#2043 name='Angelica Cuayahuitl' host='Angelica Cuayahuitl'
|
||||
router=culleoka ip=10.10.96.46 mac=58:C1:7A:AC:63:19 device=Cambium ePMP
|
||||
account=#215 name='Kileigh Even' host='Kileigh Even'
|
||||
router=culleoka ip=10.10.96.5 mac=58:C1:7A:AC:5F:11 device=Cambium ePMP
|
||||
account=#1538 name='Shirley Elmore' host='Shirley Elmore'
|
||||
router=culleoka ip=10.10.96.50 mac=00:04:56:DC:73:6B device=Ubiquiti (legacy)
|
||||
account=#10027 name='Irene Garibay' host='Irene Garibay'
|
||||
router=culleoka ip=10.10.96.51 mac=00:04:56:2E:B7:6C device=Ubiquiti (legacy)
|
||||
account=#1316 name='Iris Delira' host='Iris Delira'
|
||||
router=culleoka ip=10.10.96.53 mac=00:04:56:DC:6B:55 device=Ubiquiti (legacy)
|
||||
account=#10052 name='Khushboo Agarwal' host='Khushboo Agarwal'
|
||||
router=culleoka ip=10.10.96.54 mac=00:04:56:44:54:0A device=Ubiquiti (legacy)
|
||||
account=#2046 name='HEATHER WOMACK' host='Heather Womack'
|
||||
router=culleoka ip=10.10.96.55 mac=00:04:56:44:50:AA device=Ubiquiti (legacy)
|
||||
account=#2023 name='Billy Horton' host='Billy Horton'
|
||||
router=culleoka ip=10.10.96.58 mac=58:C1:7A:B0:B6:1F device=Cambium ePMP
|
||||
account=#1128 name='Patricia Vasquez' host='Patricia Vasquez'
|
||||
router=culleoka ip=10.10.96.65 mac=58:C1:7A:B0:D7:0D device=Cambium ePMP
|
||||
account=#1601 name='Jerid Rutledge' host='Jerid Rutledge'
|
||||
router=culleoka ip=10.10.96.67 mac=00:04:56:DC:6C:9F device=Ubiquiti (legacy)
|
||||
account=#293 name='Jeff Harder' host='Jeff Harder'
|
||||
router=culleoka ip=10.10.96.7 mac=58:C1:7A:B3:06:A8 device=Cambium ePMP
|
||||
account=#875 name='Ken Patrick' host='Ken Patrick'
|
||||
router=culleoka ip=10.10.96.72 mac=00:04:56:DC:67:59 device=Ubiquiti (legacy)
|
||||
account=#1467 name='Terri Mack' host='Terri Mack'
|
||||
router=culleoka ip=10.10.96.73 mac=00:04:56:DC:59:A6 device=Ubiquiti (legacy)
|
||||
account=#427 name='Ausencio Luna' host='Ausencio Luna'
|
||||
router=culleoka ip=10.10.96.77 mac=00:04:56:DB:C2:11 device=Ubiquiti (legacy)
|
||||
account=#433 name='Balnca Diaz' host='Balnca Diaz'
|
||||
router=culleoka ip=10.10.96.84 mac=00:04:56:DC:6D:77 device=Ubiquiti (legacy)
|
||||
account=#1712 name='Bobby Mack' host='Bobby Mack'
|
||||
router=culleoka ip=10.10.96.9 mac=00:04:56:48:66:E3 device=Ubiquiti (legacy)
|
||||
account=#10024 name='Janis Stewart' host='Janis Stewart'
|
||||
router=culleoka ip=10.10.96.91 mac=58:C1:7A:B3:08:B8 device=Cambium ePMP
|
||||
account=#623 name='Michael Newby' host='Michael Newby'
|
||||
router=culleoka ip=10.10.96.95 mac=00:04:56:4A:15:B5 device=Ubiquiti (legacy)
|
||||
account=#10073 name='Jeffrey Harder' host='Jeffrey Harder'
|
||||
router=lowry ip=10.10.144.10 mac=00:04:56:2F:DC:4C device=Ubiquiti (legacy)
|
||||
account=#10040 name='Thomas Graham' host='Thomas Graham'
|
||||
router=lowry ip=10.10.144.11 mac=58:C1:7A:AC:6A:C3 device=Cambium ePMP
|
||||
account=#10059 name='Nicholas Terry' host='Nicholas Terry'
|
||||
router=lowry ip=10.10.144.16 mac=00:04:56:4A:13:7E device=Ubiquiti (legacy)
|
||||
account=#1441 name='Doris Avalos' host='Doris Avalos'
|
||||
router=lowry ip=10.10.144.2 mac=00:04:56:2F:CD:C7 device=Ubiquiti (legacy)
|
||||
account=#84 name='Coy Ungemach' host='Coy Ungemach'
|
||||
router=lowry ip=10.10.144.20 mac=58:C1:7A:B0:F7:8F device=Cambium ePMP
|
||||
account=#224 name='Leonard Lewis' host='Leonard Lewis'
|
||||
router=lowry ip=10.10.144.24 mac=00:04:56:DC:79:38 device=Ubiquiti (legacy)
|
||||
account=#477 name='Helen Lumpkin' host='Helen Lumpkin'
|
||||
router=lowry ip=10.10.144.25 mac=00:04:56:DC:72:2A device=Ubiquiti (legacy)
|
||||
account=#735 name='FRED HECKEL' host='Fred Heckel'
|
||||
router=lowry ip=10.10.144.27 mac=00:04:56:DB:E8:D5 device=Ubiquiti (legacy)
|
||||
account=#990 name='Jennifer Dunaway' host='Jennifer Dunaway'
|
||||
router=lowry ip=10.10.144.31 mac=00:04:56:DC:6A:65 device=Ubiquiti (legacy)
|
||||
account=#345 name='Tim Fisher' host='Tim Fisher'
|
||||
router=lowry ip=10.10.144.32 mac=00:04:56:DB:AA:E6 device=Ubiquiti (legacy)
|
||||
account=#815 name='Terry Gortney' host='Terry Gortney'
|
||||
router=lowry ip=10.10.144.35 mac=00:04:56:DC:5D:63 device=Ubiquiti (legacy)
|
||||
account=#243 name='Mark Nunnelee' host='Mark Nunnelee'
|
||||
router=lowry ip=10.10.144.36 mac=00:04:56:DC:60:8D device=Ubiquiti (legacy)
|
||||
account=#1081 name='Abbie Andrews' host='Abbie Andrews'
|
||||
router=lowry ip=10.10.144.4 mac=00:04:56:DC:04:EF device=Ubiquiti (legacy)
|
||||
account=#301 name='Ron Berger' host='Ron Berger'
|
||||
router=lowry ip=10.10.144.6 mac=58:C1:7A:AD:15:7B device=Cambium ePMP
|
||||
account=#1906 name='Georgina Covarrubias' host='Georgina Covarrubias'
|
||||
router=lowry ip=10.10.144.7 mac=00:04:56:DC:72:24 device=Ubiquiti (legacy)
|
||||
account=#339 name='Terry Miesen' host='Terry Miesen'
|
||||
router=lowry ip=10.10.158.247 mac=58:C1:7A:AD:1F:20 device=Cambium ePMP
|
||||
account=#246 name='Matt Budjenska' host='Matt Budjenska'
|
||||
router=newhope ip=10.10.128.1 mac=58:C1:7A:B0:B7:AE device=Cambium ePMP
|
||||
account=#1950 name='Leandra Beshea' host='Leandra Beshea'
|
||||
router=newhope ip=10.10.128.11 mac=00:04:56:2F:D9:10 device=Ubiquiti (legacy)
|
||||
account=#1971 name='Clifford Jennings' host='Clifford M Jennings'
|
||||
router=newhope ip=10.10.128.13 mac=00:04:56:DB:97:F9 device=Ubiquiti (legacy)
|
||||
account=#848 name='Douglas Wilson' host='Douglas Wilson'
|
||||
router=newhope ip=10.10.128.14 mac=58:C1:7A:AD:13:D7 device=Cambium ePMP
|
||||
account=#100 name='Dave Kiowski' host='Dave Kiowski'
|
||||
router=newhope ip=10.10.128.18 mac=00:04:56:4A:17:B3 device=Ubiquiti (legacy)
|
||||
account=#2027 name='Chris Clayton' host='Chris Clayton'
|
||||
router=newhope ip=10.10.128.25 mac=00:04:56:44:5A:37 device=Ubiquiti (legacy)
|
||||
account=#997 name='Heather Brister' host='Heather Brister 2'
|
||||
router=newhope ip=10.10.128.28 mac=00:04:56:DC:69:F0 device=Ubiquiti (legacy)
|
||||
account=#2458 name='Marcus Patton' host='Marcus Patton'
|
||||
router=newhope ip=10.10.128.3 mac=00:04:56:DB:E7:4C device=Ubiquiti (legacy)
|
||||
account=#46 name='Bernard Heer' host='Bernard Heer'
|
||||
router=newhope ip=10.10.128.32 mac=00:04:56:44:52:ED device=Ubiquiti (legacy)
|
||||
account=#318 name='Shannon Brown' host='Shannon Brown'
|
||||
router=newhope ip=10.10.128.33 mac=00:04:56:DC:5E:50 device=Ubiquiti (legacy)
|
||||
account=#2465 name='Kory Biggs' host='Kory Biggs'
|
||||
router=newhope ip=10.10.128.34 mac=00:04:56:44:50:68 device=Ubiquiti (legacy)
|
||||
account=#1949 name='RICHARD CONKLIN' host='Richard Conklin'
|
||||
router=newhope ip=10.10.128.35 mac=58:C1:7A:AC:5A:E5 device=Cambium ePMP
|
||||
account=#2489 name='Martha Flores' host='Martha Flores'
|
||||
router=newhope ip=10.10.128.37 mac=00:04:56:DC:06:B7 device=Ubiquiti (legacy)
|
||||
account=#568 name='Frances Kirby' host='Frances Kirby'
|
||||
router=newhope ip=10.10.128.43 mac=58:C1:7A:AC:E8:81 device=Cambium ePMP
|
||||
account=#2492 name='Kory Biggs Shop' host='Kory Biggs Shop'
|
||||
router=newhope ip=10.10.128.45 mac=00:04:56:DC:05:04 device=Ubiquiti (legacy)
|
||||
account=#556 name='Mike Bell' host='Mike Bell'
|
||||
router=newhope ip=10.10.128.48 mac=00:04:56:2F:DA:E7 device=Ubiquiti (legacy)
|
||||
account=#2010 name='Brady Clayton' host='Brady Clayton'
|
||||
router=newhope ip=10.10.128.50 mac=58:C1:7A:B0:D0:20 device=Cambium ePMP
|
||||
account=#997 name='Heather Brister' host='Heather Brister'
|
||||
router=newhope ip=10.10.128.51 mac=00:04:56:DC:71:E8 device=Ubiquiti (legacy)
|
||||
account=#1879 name='Chris Telles' host='Chris Telles'
|
||||
router=newhope ip=10.10.128.52 mac=00:04:56:DC:6A:0B device=Ubiquiti (legacy)
|
||||
account=#1585 name='Tim Thomas' host='Tim Thomas'
|
||||
router=newhope ip=10.10.128.54 mac=00:04:56:DC:66:06 device=Ubiquiti (legacy)
|
||||
account=#146 name='Geok Choon Pang' host='Geok Choon Pang'
|
||||
router=newhope ip=10.10.128.6 mac=58:C1:7A:B0:F8:49 device=Cambium ePMP
|
||||
account=#2280 name='Ken Hall' host='Ken Hall'
|
||||
router=newhope ip=10.10.128.63 mac=58:C1:7A:B1:04:8B device=Cambium ePMP
|
||||
account=#2292 name='Joe Speciale' host='Joe Speciale'
|
||||
router=newhope ip=10.10.128.8 mac=00:04:56:DB:EB:78 device=Ubiquiti (legacy)
|
||||
account=#809 name='Brad Gurney' host='Brad Gurney'
|
||||
router=newhope ip=10.10.142.252 mac=58:C1:7A:B0:C1:3B device=Cambium ePMP
|
||||
account=#2295 name='Christine Hamparyan' host='Christine Hamparyan'
|
||||
router=newhope ip=10.10.142.253 mac=58:C1:7A:B1:05:D2 device=Cambium ePMP
|
||||
account=#2218 name='Greg Hummel' host='Greg Hummel'
|
||||
229
docs/plans/2026-05-14-ipv6-traceroute-collapse-6pe.md
Normal file
229
docs/plans/2026-05-14-ipv6-traceroute-collapse-6pe.md
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
# IPv6 Traceroute Collapse (6PE) Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Make IPv6 traffic transit the vntx backbone as MPLS-labeled frames so `traceroute6` collapses the internal core to ~1 hop, matching the existing IPv4 behaviour.
|
||||
|
||||
**Architecture:** Today LDP is IPv4-only and `/mpls settings propagate-ttl=no` is set fleet-wide, so labeled IPv4 hides the core. IPv6 is forwarded natively (hop-limit decremented every hop). To get the same collapse, IPv6 must ride the existing IPv4 LSPs — either via **6PE** (RFC 4798: labeled-unicast IPv6 in the global table, BGP next-hop = IPv4 loopback) or **VPNv6** (IPv6 in a VRF over the v4 core). Both are unproven on this fleet, so this plan is **spike-first**: Phase 1 is a disposable lab that produces a hard go/no-go before any production router is touched.
|
||||
|
||||
**Tech Stack:** RouterOS 7.21.4 (8 tower routers, arm64/tile), RouterOS 6.49.18 (edge), MP-BGP, LDP, OSPFv2/v3, Proxmox + CHR for the lab.
|
||||
|
||||
---
|
||||
|
||||
## Why this plan is spike-first (read before doing anything)
|
||||
|
||||
Verified facts that make the production syntax **unknowable today**:
|
||||
|
||||
1. **ROS7 6PE is undocumented.** MikroTik's MPLS Overview page never names 6PE. Community testing (forum, v7.8 CHR) reports "mixed/uncertain" results. There is no authoritative config reference.
|
||||
2. **Possible hard conflict with the existing v6 iBGP.** The fleet already runs `afi=ipv6` iBGP (tower → core RR → edge) to carry the per-tower `/44` aggregates. A third-party note (netlab) states you *cannot run 6PE and plain IPv6 BGP-LU on the same node*. If that holds on ROS7, 6PE would **replace**, not augment, the current v6 iBGP — a much larger change.
|
||||
3. **edge is RouterOS 6.49.18.** It is the PE toward TWC (AS11427). ROS6's MPLS/BGP stack is entirely separate from ROS7's, and ROS6 6PE support is at least as questionable. edge may need to stay native-v6 (its single upstream hop is cosmetically irrelevant anyway).
|
||||
|
||||
Therefore: **no production router is reconfigured until Phase 1 proves the mechanism in a lab and answers conflict-question #2.** Phases 2–4 deliberately do not contain exact commands — they are filled in from the spike's findings (Task 1.7).
|
||||
|
||||
**If you are tempted to skip Phase 1: don't.** A half-working 6PE deployment black-holes customer IPv6 fleet-wide.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Lab spike (disposable, zero production impact)
|
||||
|
||||
Build a 3-router CHR lab on graham's home Proxmox that mirrors a slice of the
|
||||
backbone (`edge′ — core′ — verona′`) plus a CE host at each end, prove that
|
||||
labeled IPv6 collapses `traceroute6`, and determine whether 6PE coexists with
|
||||
plain IPv6 iBGP.
|
||||
|
||||
**Topology:**
|
||||
```
|
||||
[CE-A]──ce-a/v6──[verona′]──p2p v4 LDP──[core′]──p2p v4 LDP──[edge′]──ce-b/v6──[CE-B]
|
||||
2606:db8:a::/64 2606:db8:b::/64
|
||||
loopbacks: verona′ 10.0.0.1 core′ 10.0.0.2 edge′ 10.0.0.3 (v6: 2606:db8:0:10::1/2/3)
|
||||
```
|
||||
CE-A/CE-B can be CHRs or any Linux VM — they just need an IPv6 address and `traceroute6`.
|
||||
|
||||
### Task 1.1: Stand up the CHR lab VMs
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/plans/lab/6pe-lab-notes.md` (running log of what works — this becomes the source for Phases 2–4)
|
||||
|
||||
**Step 1:** On Proxmox, import the RouterOS CHR image (https://mikrotik.com/download → "Cloud Hosted Router" → 7.21.4 stable VMDK/qcow2). Create 5 VMs: `verona-lab`, `core-lab`, `edge-lab`, `ce-a`, `ce-b`. 256 MB RAM / 1 vCPU each is plenty. CHR is licence-free at ≤1 Mbps — fine for a lab.
|
||||
|
||||
**Step 2:** Create 4 isolated Proxmox bridges (no uplink): `vmbr-cea`, `vmbr-vc` (verona′↔core′), `vmbr-ce` (core′↔edge′), `vmbr-ceb`. Wire NICs:
|
||||
- verona-lab: eth1→vmbr-cea, eth2→vmbr-vc
|
||||
- core-lab: eth1→vmbr-vc, eth2→vmbr-ce
|
||||
- edge-lab: eth1→vmbr-ce, eth2→vmbr-ceb
|
||||
- ce-a: eth1→vmbr-cea ; ce-b: eth1→vmbr-ceb
|
||||
|
||||
**Step 3:** Boot all 5. Confirm console login on each.
|
||||
|
||||
**Step 4 (commit):**
|
||||
```bash
|
||||
cd /Users/graham/dev/network
|
||||
git add docs/plans/lab/6pe-lab-notes.md
|
||||
git commit -m "6pe lab: stand up 5-VM CHR topology"
|
||||
```
|
||||
Expected: lab notes file committed with the topology + VM IDs recorded.
|
||||
|
||||
### Task 1.2: Build the IPv4 + LDP core (mirror of production)
|
||||
|
||||
**Step 1:** On each lab router configure loopback, p2p /30s, OSPFv2, LDP, and `propagate-ttl=no` — a scaled-down copy of the real fleet. Example for `core-lab` (adapt addresses per router):
|
||||
```rsc
|
||||
/interface bridge add name=lo
|
||||
/ip address add address=10.0.0.2/32 interface=lo
|
||||
/ip address add address=10.1.12.2/30 interface=ether1 ;; to verona′
|
||||
/ip address add address=10.1.23.1/30 interface=ether2 ;; to edge′
|
||||
/routing ospf instance add name=v2 router-id=10.0.0.2
|
||||
/routing ospf area add name=backbone instance=v2 area-id=0.0.0.0
|
||||
/routing ospf interface-template add area=backbone interfaces=lo passive
|
||||
/routing ospf interface-template add area=backbone interfaces=ether1,ether2 type=ptp
|
||||
/mpls ldp add lsr-id=10.0.0.2 transport-addresses=10.0.0.2
|
||||
/mpls ldp interface add interface=ether1
|
||||
/mpls ldp interface add interface=ether2
|
||||
/mpls settings set propagate-ttl=no
|
||||
```
|
||||
|
||||
**Step 2: Verify the v4 core.** From `verona-lab`:
|
||||
```rsc
|
||||
/routing ospf neighbor print ;; expect Full to core′
|
||||
/mpls ldp neighbor print ;; expect operational to core′
|
||||
/mpls forwarding-table print ;; expect labels for 10.0.0.2, 10.0.0.3
|
||||
/tool traceroute 10.0.0.3 ;; edge′ loopback — expect 1 hop (LDP + propagate-ttl=no)
|
||||
```
|
||||
Expected: traceroute to the far loopback shows **one hop**. This proves the lab reproduces the production v4 collapse. If it does not, fix the lab before continuing — Phase 1's whole value is a faithful mirror.
|
||||
|
||||
**Step 3 (commit):** Record the working core configs in `6pe-lab-notes.md`, commit.
|
||||
|
||||
### Task 1.3: Baseline — native IPv6, measure the problem
|
||||
|
||||
**Step 1:** Add native IPv6 + OSPFv3 across the lab core (loopbacks `2606:db8:0:10::1/2/3`, p2p `2606:db8:0:1N::/64`), and give CE-A/CE-B addresses in `2606:db8:a::/64` and `2606:db8:b::/64` with static routes or OSPFv3.
|
||||
|
||||
**Step 2: Measure baseline.** From CE-A:
|
||||
```
|
||||
traceroute6 2606:db8:b::1
|
||||
```
|
||||
Expected: **3+ hops** (verona′, core′, edge′ each appear). Record exact output in lab notes — this is the "before".
|
||||
|
||||
**Step 3 (commit):** Commit lab notes with the native-v6 baseline traceroute.
|
||||
|
||||
### Task 1.4: Add the existing-style IPv6 iBGP (reproduce the conflict surface)
|
||||
|
||||
**Step 1:** Configure v6 iBGP exactly like production: `verona-lab` and `edge-lab` as RR-clients of `core-lab`, `afi=ip,ipv6`, sessions over the v6 loopbacks, redistributing connected. This is the config that 6PE may conflict with.
|
||||
|
||||
**Step 2: Verify** v6 iBGP sessions establish and the CE prefixes are learned. Record in lab notes.
|
||||
|
||||
**Step 3 (commit).**
|
||||
|
||||
### Task 1.5: Attempt 6PE — the actual unknown
|
||||
|
||||
**This is the discovery task. Do not fabricate commands — find them.**
|
||||
|
||||
**Step 1:** Read, in this order, and capture findings in lab notes:
|
||||
- MikroTik MPLS Overview + BGP doc pages (help.mikrotik.com) — search for "label", "ipv6", "6PE", "labeled-unicast".
|
||||
- `/routing bgp connection` and `/routing bgp template` — dump every available property on a lab router (`/routing bgp connection print detail` on a connection with all afi values; try `afi=ipv6` plus any label-related sub-property the CLI tab-completes).
|
||||
- The MikroTik forum thread "IPv6-on-MPLS BGP-free Core?" for working/failing examples.
|
||||
|
||||
**Step 2:** On the lab, attempt 6PE: make the v6 iBGP advertise labeled IPv6 with BGP next-hop = the IPv4 loopback (as `::ffff:10.0.0.x`). Try it **alongside** the Task 1.4 plain v6 iBGP first.
|
||||
|
||||
**Step 3: Decision question A — coexistence.** Does enabling 6PE break or get rejected next to the plain `afi=ipv6` iBGP? Record the exact behaviour. If they cannot coexist, note that production Phase 3 must *replace* the v6 iBGP, and re-test 1.5 with the plain v6 iBGP removed.
|
||||
|
||||
**Step 4 (commit):** Lab notes updated with the exact 6PE config that loads without error (or the proof that it can't).
|
||||
|
||||
### Task 1.6: Verify the collapse (the success criterion)
|
||||
|
||||
**Step 1:** Confirm labels are bound to IPv6 routes:
|
||||
```rsc
|
||||
/mpls forwarding-table print ;; expect 2606:db8:b::/64 etc. with a label
|
||||
```
|
||||
|
||||
**Step 2:** From CE-A:
|
||||
```
|
||||
traceroute6 2606:db8:b::1
|
||||
```
|
||||
**Success = 1 hop across the lab core** (or core′ invisible), matching the v4 behaviour from Task 1.2.
|
||||
|
||||
**Step 3:** Failure-mode checks — confirm nothing else broke:
|
||||
- CE-A ↔ CE-B large-packet ping (`ping6 -s 1452`) — no new MTU loss (label adds 4 bytes; lab p2p MTU must have headroom, same as the real `mpls-mtu=1508`).
|
||||
- Kill the `core-lab`↔`edge-lab` link, confirm v6 reconverges (or fails predictably).
|
||||
|
||||
**Step 4 (commit):** Lab notes updated with the before/after traceroute and the failure-mode results.
|
||||
|
||||
### Task 1.7: Write the go/no-go and fill in Phases 2–4
|
||||
|
||||
**Step 1:** In `6pe-lab-notes.md`, write a **GO / NO-GO** verdict answering:
|
||||
- Does labeled IPv6 collapse `traceroute6` on ROS 7.21.4? (Task 1.6)
|
||||
- Can 6PE coexist with the existing v6 iBGP, or must it replace it? (Task 1.5 Step 3)
|
||||
- What is the **exact, tested** per-router 6PE config delta?
|
||||
- Does anything require an MTU change beyond the existing `mpls-mtu=1508`?
|
||||
|
||||
**Step 2:** If **GO**: replace the "TBD pending spike" bodies of Phase 2 and Phase 3 below with the exact tested commands from the lab. If **NO-GO**: stop here, jump to "Alternatives", and bring the recommendation to graham.
|
||||
|
||||
**Step 3 (commit):**
|
||||
```bash
|
||||
git add docs/plans/lab/6pe-lab-notes.md docs/plans/2026-05-14-ipv6-traceroute-collapse-6pe.md
|
||||
git commit -m "6pe lab: go/no-go verdict + fill production phases"
|
||||
```
|
||||
|
||||
### Task 1.8: Tear down the lab
|
||||
|
||||
**Step 1:** Delete the 5 CHR VMs and 4 Proxmox bridges. The lab notes (committed) are the deliverable; the VMs are disposable.
|
||||
|
||||
**Step 2 (commit):** Note teardown in lab notes, commit.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Production pilot: verona ↔ climax ↔ core *(contingent on Phase 1 = GO)*
|
||||
|
||||
**Body TBD — populated from Task 1.7.** Constraints the filled-in version must honour:
|
||||
|
||||
- **Apply order matters.** Bring up the labeled-v6 path core-first, then climax, then verona, so a tower is never advertising labeled v6 toward a router that can't resolve it.
|
||||
- **One change window, one link triangle.** Pilot only verona/climax/core; do not touch the other 5 towers until the pilot soaks ≥24h.
|
||||
- **Each router task = change → verify → rollback-ready**, e.g.:
|
||||
- apply 6PE delta on core
|
||||
- `/mpls forwarding-table print` shows labels for the pilot towers' v6
|
||||
- `/routing bgp advertisements` / `/routing route print` confirms labeled v6 NLRI
|
||||
- from graham's home Mac: `traceroute6` to an off-net v6 host — core no longer a distinct hop
|
||||
- `ping6 -s 1452` to `2606:4700:4700::1111` still 0% loss
|
||||
- customer-facing: a known v6 PPPoE/wired client still reaches the internet
|
||||
- **Rollback (per router):** the inverse delta, recorded in Task 1.7. Native v6 + OSPFv3 + the existing v6 iBGP must still be present underneath (do not delete them in the pilot — if 6PE coexists, native is the fallback; if it doesn't, Phase 2 rollback = re-add v6 iBGP).
|
||||
- **Soak gate:** 24h with no v6 customer complaints + traceroute stays collapsed before Phase 3.
|
||||
|
||||
## Phase 3 — Fleet rollout: culleoka, newhope, lowry, 982, 494 *(contingent)*
|
||||
|
||||
**Body TBD — populated from Task 1.7.** Constraints:
|
||||
|
||||
- Roll out in the CGNAT-renumber order from `subnets.md` (one tower per change window).
|
||||
- Same per-router verify set as Phase 2.
|
||||
- newhope carries lowry's transit — do newhope before lowry.
|
||||
- After each tower: `traceroute6` from home Mac still collapsed, customer v6 spot-check.
|
||||
- Keep `mikrotik-tool` (`api`/`script`) as the push mechanism; one `.rsc` per router or a templated apply.
|
||||
|
||||
## Phase 4 — edge (RouterOS 6.49.18) *(contingent, likely "leave native")*
|
||||
|
||||
**Body TBD.** Default expectation from Phase 1 framing point #3: **edge stays native IPv6.** edge is one hop from core and one hop from TWC — collapsing it changes nothing a user sees. Only revisit if Task 1.7 specifically finds ROS6 6PE both works and is needed. If edge stays native, document that the v6 path is "labeled across the ROS7 core, native for the edge↔TWC hop" so the next operator isn't surprised.
|
||||
|
||||
---
|
||||
|
||||
## Rollback (whole project)
|
||||
|
||||
- **Phase 1:** delete VMs. Nothing to roll back.
|
||||
- **Phase 2/3:** per-router inverse delta from Task 1.7, applied in reverse order (towers before core). Native v6 forwarding + OSPFv3 are never removed during pilot/rollout, so the floor is always "back to today's working native v6."
|
||||
- **Trigger:** any v6 customer outage, `traceroute6` black-holing (not just collapsing), or MTU loss that won't resolve.
|
||||
- The firewall, DNS, and home-router work already done (forward `accept src 2606:1c80::/32`, `v6-dns` resolvers, home `/56`) are **independent of this plan** and are not touched by any phase.
|
||||
|
||||
---
|
||||
|
||||
## Alternatives (if Phase 1 = NO-GO)
|
||||
|
||||
| Option | What it gives | Cost / risk |
|
||||
|---|---|---|
|
||||
| **Do nothing** | v6 traceroute keeps showing the core (internal hops currently appear as `*` — they don't even reply). Everything works. | Zero. The collapse is cosmetic. |
|
||||
| **VPNv6** | IPv6 in a VRF over the v4 core — *is* labeled, so traceroute collapses. ROS7 documents `vpnv6`. | Large: every router's customer v6 (addresses, pools, PPP profiles, firewall, the home `/56`) moves into a VRF. Much bigger blast radius than 6PE. |
|
||||
| **Make internal hops reply instead of hiding them** | Opposite of the goal, but "honest" traceroute — each router answers with ICMPv6 time-exceeded. | Small `chain=input` tweak. Only relevant if the real annoyance is the `* * *` lines, not the hop count. |
|
||||
|
||||
**Recommendation if NO-GO:** do nothing. The IPv4 collapse is a side-effect of MPLS existing for real routing reasons; chasing the same cosmetics for IPv6 via a VRF migration is not worth the blast radius. Revisit only if MikroTik documents real 6PE support in a later ROS7 release.
|
||||
|
||||
---
|
||||
|
||||
## Open questions for graham (resolve before Phase 2, ideally before Phase 1)
|
||||
|
||||
1. Is collapsing v6 traceroute worth a multi-window backbone change, or is it "nice to have"? (Sets how hard to push past a marginal Phase 1 result.)
|
||||
2. Proxmox capacity at home for 5 throwaway CHR VMs — OK to spin up?
|
||||
3. edge's eventual ROS6→ROS7 upgrade — if that's on the roadmap anyway, Phase 4 should wait for it rather than attempt ROS6 6PE.
|
||||
3
gaiia/.direnv
Normal file
3
gaiia/.direnv
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export GAIIA_KEY=gaiia_sk_live_955b27e3680747a69ad40b403a912155_b0d1be3c
|
||||
export EXPIRE_WF_ID=workflow_gbL1BTRA5Xt4WkMy2uRLdW
|
||||
|
||||
2
gaiia/.envrc
Normal file
2
gaiia/.envrc
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export GAIIA_KEY=gaiia_sk_live_955b27e3680747a69ad40b403a912155_b0d1be3c
|
||||
|
||||
17
gaiia/.gitignore
vendored
Normal file
17
gaiia/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
build/
|
||||
dist/
|
||||
.venv/
|
||||
venv/
|
||||
.env
|
||||
.envrc.local
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
.ruff_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
*.swp
|
||||
.DS_Store
|
||||
21
gaiia/LICENSE
Normal file
21
gaiia/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 Graham McIntire
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
198
gaiia/README.md
Normal file
198
gaiia/README.md
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
# gaiia-py
|
||||
|
||||
Python client for the [gaiia](https://app.gaiia.com/docs/overview) GraphQL API
|
||||
and webhooks. Thin wrapper around the official GraphQL surface — no codegen, no
|
||||
opinionated ORM. You write GraphQL, the client handles auth, pagination, rate
|
||||
limits, GlobalID encoding, and webhook signature verification.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
pip install gaiia
|
||||
```
|
||||
|
||||
Requires Python 3.10+. Depends on `httpx`.
|
||||
|
||||
## Quick start
|
||||
|
||||
```python
|
||||
from gaiia import GaiiaClient
|
||||
|
||||
with GaiiaClient(api_key="gaiia_sk_live_...", timezone="America/Chicago") as g:
|
||||
data = g.query(
|
||||
"query Q($first: Int!) { technicians(first: $first) { nodes { id firstName lastName } } }",
|
||||
{"first": 10},
|
||||
)
|
||||
for t in data["technicians"]["nodes"]:
|
||||
print(t)
|
||||
```
|
||||
|
||||
If `api_key=` is omitted, the client reads `GAIIA_KEY` from the environment.
|
||||
|
||||
## Mutations
|
||||
|
||||
The `mutate()` helper unwraps the mutation result and raises
|
||||
`GaiiaMutationError` when the response contains validation errors under
|
||||
`data.<mutation>.errors`:
|
||||
|
||||
```python
|
||||
res = g.mutate(
|
||||
"""
|
||||
mutation A($i: AssignTechnicianToWorkOrderInput!) {
|
||||
assignTechnicianToWorkOrder(input: $i) {
|
||||
workOrder { id status startDate }
|
||||
errors { code message }
|
||||
}
|
||||
}
|
||||
""",
|
||||
"assignTechnicianToWorkOrder",
|
||||
{"i": {
|
||||
"workOrderId": "work_order_...",
|
||||
"technicianId": "technician_...",
|
||||
"startDate": "2026-05-12T14:00:00Z",
|
||||
}},
|
||||
)
|
||||
print(res["workOrder"]["id"])
|
||||
```
|
||||
|
||||
## Pagination
|
||||
|
||||
`iter_nodes()` paginates a Relay Connection automatically. Your query must
|
||||
accept an `$after: String` variable and pass it to the paginated field:
|
||||
|
||||
```python
|
||||
for tech in g.iter_nodes(
|
||||
"""
|
||||
query Q($after: String) {
|
||||
technicians(first: 50, after: $after) {
|
||||
nodes { id firstName lastName }
|
||||
pageInfo { hasNextPage endCursor }
|
||||
}
|
||||
}
|
||||
""",
|
||||
"technicians",
|
||||
):
|
||||
print(tech["firstName"], tech["lastName"])
|
||||
```
|
||||
|
||||
Default page size is 50, max 250 (per the gaiia docs). Some fields cap lower —
|
||||
check the field's reference page.
|
||||
|
||||
For bulk extracts (millions of rows, reporting, analytics), gaiia recommends
|
||||
[Snowflake](https://app.gaiia.com/docs/rate-limits) rather than the GraphQL
|
||||
API.
|
||||
|
||||
## Rate limiting
|
||||
|
||||
After every call, `client.last_rate_limit` is populated from the response
|
||||
headers (`X-Rate-Limit-*`). If gaiia returns a `RATE_LIMITED` error, the
|
||||
client raises `GaiiaRateLimitedError` with `limit`, `used`, `remaining`, and
|
||||
`retry_at`:
|
||||
|
||||
```python
|
||||
from gaiia import GaiiaClient, GaiiaRateLimitedError
|
||||
|
||||
with GaiiaClient(max_retries=2) as g:
|
||||
try:
|
||||
g.query("{ ... }")
|
||||
except GaiiaRateLimitedError as e:
|
||||
print("retry after", e.retry_at)
|
||||
```
|
||||
|
||||
Setting `max_retries` > 0 makes the client sleep until `retry_at` and retry up
|
||||
to that many times before re-raising.
|
||||
|
||||
## GlobalIDs
|
||||
|
||||
```python
|
||||
from gaiia import encode_global_id, decode_global_id
|
||||
|
||||
encode_global_id("Account", "3c3b1978-6a68-4a13-bdc2-2d51c8ef7519")
|
||||
# 'account_8rnXNuR5sKP5uNwoPL41Zp'
|
||||
|
||||
decode_global_id("account_8rnXNuR5sKP5uNwoPL41Zp")
|
||||
# ('account', '3c3b1978-6a68-4a13-bdc2-2d51c8ef7519')
|
||||
```
|
||||
|
||||
The encoding follows gaiia's `short-uuid` setup: Flickr Base-58 of the UUID's
|
||||
128-bit integer, left-padded to 22 chars, prefixed with the snake-cased type.
|
||||
|
||||
## Webhooks
|
||||
|
||||
```python
|
||||
from gaiia import verify_webhook_signature, WebhookSignatureError
|
||||
|
||||
try:
|
||||
verify_webhook_signature(
|
||||
header_value=request.headers["X-Gaiia-Webhook-Signature"],
|
||||
raw_body=request.body_bytes, # the exact bytes gaiia signed
|
||||
secret=os.environ["GAIIA_WEBHOOK_SECRET"],
|
||||
tolerance_seconds=300,
|
||||
)
|
||||
except WebhookSignatureError:
|
||||
return 400
|
||||
```
|
||||
|
||||
The verifier:
|
||||
|
||||
- Parses `t=...,v1=...` (multiple `v1=` allowed for key rotation),
|
||||
- Computes `HMAC-SHA256(secret, "${t}.${rawBody}")`,
|
||||
- Constant-time compares against each `v1=` candidate,
|
||||
- Rejects timestamps outside the tolerance window.
|
||||
|
||||
See `examples/webhook_flask.py` for a complete handler.
|
||||
|
||||
## Async
|
||||
|
||||
`AsyncGaiiaClient` mirrors `GaiiaClient` for `asyncio` code:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from gaiia import AsyncGaiiaClient
|
||||
|
||||
async def main():
|
||||
async with AsyncGaiiaClient(timezone="America/Chicago") as g:
|
||||
data = await g.query("{ technicians(first: 5) { nodes { id firstName lastName } } }")
|
||||
print(data)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
`async for` over `iter_nodes()` paginates lazily.
|
||||
|
||||
## Timezones
|
||||
|
||||
gaiia stores all timestamps in UTC. Pass `timezone="America/Chicago"` (or
|
||||
whatever IANA TZ applies) at the client level — it becomes the `x-timezone`
|
||||
header on every request, which gaiia uses for scheduling/availability logic.
|
||||
Override per-call with `g.query(..., timezone="America/Phoenix")`.
|
||||
|
||||
For display, query the work order's `location.timezone` and format times in
|
||||
that zone — not the caller's.
|
||||
|
||||
## Error model
|
||||
|
||||
| Class | When it's raised |
|
||||
| ------------------------ | ---------------------------------------------------------------------- |
|
||||
| `GaiiaTransportError` | Network failure, non-JSON response, HTTP 5xx. |
|
||||
| `GaiiaAPIError` | Top-level GraphQL `errors[]` returned (schema/auth/permission). |
|
||||
| `GaiiaRateLimitedError` | Subclass of `GaiiaAPIError` for `RATE_LIMITED`. |
|
||||
| `GaiiaMutationError` | Mutation `data.<m>.errors[]` is non-empty (validation/business rule). |
|
||||
|
||||
All inherit from `GaiiaError`.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
git clone https://github.com/grahammcintire/gaiia-py
|
||||
cd gaiia-py
|
||||
python -m venv .venv && source .venv/bin/activate
|
||||
pip install -e ".[dev]"
|
||||
pytest
|
||||
ruff check .
|
||||
mypy src/gaiia
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT.
|
||||
116
gaiia/account_status_suspension_workflow.json
Normal file
116
gaiia/account_status_suspension_workflow.json
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
"name": "Account Status - RADIUS Suspension",
|
||||
"description": "EVENT: When account status changes to SUSPENDED or INACTIVE, update RADIUS usergroup to suspended. When it returns to ACTIVE, restore normal groups.",
|
||||
"trigger": {
|
||||
"type": "EVENT",
|
||||
"events": ["account.status_updated"],
|
||||
"nextSteps": [{ "slug": "get-account" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Get account status and products",
|
||||
"slug": "get-account",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output, state }) => {\n const acct = output.response.account;\n if (!acct) {\n workflow.fail('Account not found', 'ACCOUNT_NOT_FOUND');\n }\n const status = acct.status?.name?.toUpperCase() || '';\n const products = [];\n for (const sub of (acct.billingSubscriptions?.nodes || [])) {\n const p = sub.productVersion?.product;\n if (p && !products.includes(p.id)) {\n products.push(p.id);\n }\n }\n return { status, products, accountId: acct.id };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query GetAccount($id: GlobalID!) {\n account(id: $id) {\n id\n status { name }\n billingSubscriptions {\n nodes {\n productVersion {\n product { id name }\n }\n }\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => ({ id: state.input.objectId })"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "check-radius-exists" }]
|
||||
},
|
||||
{
|
||||
"name": "Check if account has RADIUS usernames",
|
||||
"slug": "check-radius-exists",
|
||||
"type": "TYPESCRIPT_CODE",
|
||||
"nodeSlug": "execute-typescript-code",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output, state }) => {\n const acct = state.steps['get-account'].output;\n acct.hasRadius = output && output.length > 0;\n return acct;\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "function",
|
||||
"type": "FUNCTION",
|
||||
"value": "async ({ state, utils }) => {\n const { accountId } = state.steps['get-account'].output;\n const existingData = await utils.integration.datastore.getItem(`radiusAccount.${accountId}`);\n const accounts = existingData ? JSON.parse(existingData) : [];\n return accounts;\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "should-suspend" }]
|
||||
},
|
||||
{
|
||||
"name": "Should suspend?",
|
||||
"slug": "should-suspend",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const { status, hasRadius } = state.steps['check-radius-exists'].output;\n return hasRadius && (status === 'SUSPENDED' || status === 'INACTIVE');\n}",
|
||||
"elseSteps": [{ "slug": "should-reactivate" }],
|
||||
"thenSteps": [{ "slug": "update-groups-suspended" }]
|
||||
},
|
||||
{
|
||||
"name": "Update RADIUS groups to SUSPENDED",
|
||||
"slug": "update-groups-suspended",
|
||||
"type": "GAIIA_START_WORKFLOW_EXECUTION",
|
||||
"nodeSlug": "start-workflow-execution",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "workflowId",
|
||||
"type": "LITERAL",
|
||||
"value": "string:workflow_fLXTNCvridPqwEEXxf3CK1"
|
||||
},
|
||||
{
|
||||
"key": "input",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { accountId, products, status } = state.steps['check-radius-exists'].output;\n return {\n accountId,\n status,\n productIds: products\n };\n}"
|
||||
},
|
||||
{
|
||||
"key": "fireAndForget",
|
||||
"type": "LITERAL",
|
||||
"value": "boolean:true"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Should reactivate?",
|
||||
"slug": "should-reactivate",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const { status, hasRadius } = state.steps['check-radius-exists'].output;\n return hasRadius && status === 'ACTIVE';\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "update-groups-active" }]
|
||||
},
|
||||
{
|
||||
"name": "Update RADIUS groups to ACTIVE",
|
||||
"slug": "update-groups-active",
|
||||
"type": "GAIIA_START_WORKFLOW_EXECUTION",
|
||||
"nodeSlug": "start-workflow-execution",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "workflowId",
|
||||
"type": "LITERAL",
|
||||
"value": "string:workflow_fLXTNCvridPqwEEXxf3CK1"
|
||||
},
|
||||
{
|
||||
"key": "input",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { accountId, products } = state.steps['check-radius-exists'].output;\n return {\n accountId,\n status: 'ACTIVE',\n productIds: products\n };\n}"
|
||||
},
|
||||
{
|
||||
"key": "fireAndForget",
|
||||
"type": "LITERAL",
|
||||
"value": "boolean:true"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
78
gaiia/cleanup_stale_byod_workflow.json
Normal file
78
gaiia/cleanup_stale_byod_workflow.json
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"name": "Cleanup Stale BYOD Items",
|
||||
"description": "SCHEDULED (nightly 2am): Unassigns Customer Provided Router items that have no active IP assignment. Keeps items with active IPs intact.",
|
||||
"trigger": {
|
||||
"type": "SCHEDULE",
|
||||
"cron": "0 2 * * *",
|
||||
"nextSteps": [{ "slug": "find-stale-byod" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Find stale BYOD items",
|
||||
"slug": "find-stale-byod",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const items = output.response.inventoryItems.nodes;\n const stale = [];\n for (const item of items) {\n const assigns = item.ipAddressAssignments?.nodes || [];\n const hasActive = assigns.some((a) => a.isActive !== false);\n if (!hasActive) {\n const assignee = item.assignation?.assignee || {};\n if (assignee.__typename === 'Account' && assignee.id) {\n stale.push({ inventoryId: item.id, accountId: assignee.id, accountName: assignee.name || '' });\n }\n }\n }\n return stale;\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query {\n inventoryItems(\n first: 250\n filters: { modelId: { equals: \"inventory_model_522SxVU9VvPaMXYqWNbfbx\" }, assigneeType: { equals: ACCOUNT } }\n ) {\n nodes {\n id\n ipAddressAssignments {\n nodes { ipAddress macAddress isActive }\n }\n assignation {\n assignee { __typename ... on Account { id name } }\n }\n }\n totalCount\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ secrets, state, utils, variables }) => ({})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "if-any-stale" }]
|
||||
},
|
||||
{
|
||||
"name": "Any stale items?",
|
||||
"slug": "if-any-stale",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const items = state.steps['find-stale-byod'].output;\n return Array.isArray(items) && items.length > 0;\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "unassign-stale" }]
|
||||
},
|
||||
{
|
||||
"name": "Unassign each stale item",
|
||||
"slug": "unassign-stale",
|
||||
"type": "PARALLEL_LOOP",
|
||||
"nodeSlug": "parallel-loop",
|
||||
"maxConcurrentIterations": 10,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "iterable",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['find-stale-byod'].output"
|
||||
}
|
||||
],
|
||||
"initialSteps": [{ "slug": "unassign-one" }],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Unassign from account",
|
||||
"slug": "unassign-one",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"parentParallelLoopSlug": "unassign-stale",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation UnassignItem($input: UnassignCustomerOwnedItemInput!) {\n unassignCustomerOwnedItem(input: $input) {\n customerOwnedItem { id }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const item = state.currentParallelLoopIterations['unassign-stale'];\n return { input: { id: item.inventoryId } };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "unassign-stale-end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
143
gaiia/clear_all_ips.py
Normal file
143
gaiia/clear_all_ips.py
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Clear all MAC->IP address assignments from customer inventory items.
|
||||
|
||||
Two-phase approach:
|
||||
1. List all active IP assignments via paginated V1 public API
|
||||
2. Expire each one via startWorkflowExecution mutation
|
||||
|
||||
Before running:
|
||||
1. Create the "Expire Single IP Assignment" workflow in Gaiia UI
|
||||
(use expire_one_workflow.json)
|
||||
2. Copy its workflow ID and set EXPIRE_WF_ID below
|
||||
3. source .envrc
|
||||
4. uv run python3 clear_all_ips.py --dry-run (preview)
|
||||
5. uv run python3 clear_all_ips.py (execute)
|
||||
"""
|
||||
|
||||
from gaiia import GaiiaClient, GaiiaMutationError
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
EXPIRE_WF_ID = os.environ.get("EXPIRE_WF_ID", "")
|
||||
|
||||
def list_all_assignments(client):
|
||||
"""Paginate through all inventory items and return active MAC->IP pairs."""
|
||||
all_assignments = []
|
||||
after = None
|
||||
page = 0
|
||||
|
||||
while True:
|
||||
page += 1
|
||||
query = """
|
||||
query Q($after: String) {
|
||||
inventoryItems(
|
||||
filters: {assigneeType: {equals: ACCOUNT}}
|
||||
first: 250
|
||||
after: $after
|
||||
) {
|
||||
nodes {
|
||||
ipAddressAssignments {
|
||||
nodes { ipAddress macAddress isActive }
|
||||
}
|
||||
}
|
||||
pageInfo { hasNextPage endCursor }
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
"""
|
||||
data = client.query(query, {"after": after} if after else {})
|
||||
result = data['inventoryItems']
|
||||
|
||||
if page == 1:
|
||||
print(f"Total inventory items: {result['totalCount']}")
|
||||
|
||||
for item in result['nodes']:
|
||||
for a in item.get('ipAddressAssignments', {}).get('nodes', []):
|
||||
if a.get('isActive') != False:
|
||||
all_assignments.append({
|
||||
'macAddress': a['macAddress'],
|
||||
'ipAddress': a['ipAddress']
|
||||
})
|
||||
|
||||
page_info = result['pageInfo']
|
||||
sys.stderr.write(f"\r Page {page}: {len(all_assignments)} assignments so far...")
|
||||
sys.stderr.flush()
|
||||
|
||||
if not page_info.get('hasNextPage'):
|
||||
break
|
||||
after = page_info['endCursor']
|
||||
|
||||
sys.stderr.write("\n")
|
||||
return all_assignments
|
||||
|
||||
|
||||
def expire_one(client, mac_address, ip_address, dry_run=False):
|
||||
"""Call the Expire Single IP Assignment workflow via startWorkflowExecution."""
|
||||
if dry_run:
|
||||
print(f" [DRY-RUN] {mac_address} -> {ip_address}")
|
||||
return True
|
||||
|
||||
mutation = """
|
||||
mutation Expire($input: StartWorkflowExecutionInput!) {
|
||||
startWorkflowExecution(input: $input) {
|
||||
workflowExecution { id status }
|
||||
}
|
||||
}
|
||||
"""
|
||||
try:
|
||||
client.query(mutation, {
|
||||
"input": {
|
||||
"workflowId": EXPIRE_WF_ID,
|
||||
"input": {"macAddress": mac_address, "ipAddress": ip_address}
|
||||
}
|
||||
})
|
||||
return True
|
||||
except GaiiaMutationError as e:
|
||||
print(f" FAILED {mac_address} -> {ip_address}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
if not EXPIRE_WF_ID:
|
||||
print("ERROR: Set EXPIRE_WF_ID env var to the workflow ID of 'Expire Single IP Assignment'")
|
||||
print("Example: EXPIRE_WF_ID=workflow_xxx uv run python3 clear_all_ips.py --dry-run")
|
||||
sys.exit(1)
|
||||
|
||||
dry_run = "--dry-run" in sys.argv
|
||||
|
||||
with GaiiaClient(timezone='America/Chicago') as g:
|
||||
print("Listing all active IP assignments...")
|
||||
assignments = list_all_assignments(g)
|
||||
print(f"\nFound {len(assignments)} active IP assignments")
|
||||
|
||||
if dry_run:
|
||||
print("\n--dry-run mode: showing what would be expired --")
|
||||
else:
|
||||
print(f"\nExpiring via workflow {EXPIRE_WF_ID}...")
|
||||
|
||||
succeeded = 0
|
||||
failed = 0
|
||||
for i, a in enumerate(assignments):
|
||||
if not dry_run:
|
||||
sys.stderr.write(f"\r {i+1}/{len(assignments)}: {a['macAddress']} -> {a['ipAddress']}")
|
||||
sys.stderr.flush()
|
||||
if expire_one(g, a['macAddress'], a['ipAddress'], dry_run):
|
||||
succeeded += 1
|
||||
else:
|
||||
failed += 1
|
||||
if not dry_run:
|
||||
time.sleep(0.1) # avoid rate limiting
|
||||
|
||||
if not dry_run:
|
||||
sys.stderr.write("\n")
|
||||
|
||||
print(f"\nDone: {succeeded} succeeded, {failed} failed")
|
||||
if dry_run:
|
||||
print("(nothing was changed — remove --dry-run to execute)")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
85
gaiia/clear_ip_assignments_workflow.json
Normal file
85
gaiia/clear_ip_assignments_workflow.json
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"name": "Clear All IP Assignments",
|
||||
"description": "ONE-SHOT: Expires all MAC→IP address assignments across all customer inventory items. Run once, then delete this workflow.",
|
||||
"trigger": {
|
||||
"type": "MANUAL",
|
||||
"nextSteps": [
|
||||
{ "slug": "find-assigned-items" }
|
||||
]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Find all inventory items assigned to accounts",
|
||||
"slug": "find-assigned-items",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const items = output.response.inventoryItems.nodes;\n const withIps = [];\n for (const item of items) {\n const assignments = item.ipAddressAssignments?.nodes || [];\n for (const a of assignments) {\n if (a.isActive !== false) {\n withIps.push({\n macAddress: a.macAddress,\n ipAddress: a.ipAddress\n });\n }\n }\n }\n return withIps;\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query AllAssignedItems($filters: InventoryItemsQueryFilters, $first: Int, $after: String) {\n inventoryItems(filters: $filters, first: $first, after: $after) {\n nodes {\n ipAddressAssignments {\n nodes {\n ipAddress\n macAddress\n isActive\n }\n }\n }\n pageInfo { hasNextPage endCursor }\n totalCount\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "LITERAL",
|
||||
"value": "json:{\"filters\":{\"assigneeType\":{\"equals\":\"ACCOUNT\"}},\"first\":250}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
{ "slug": "if-any-assignments" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Any assignments to clear?",
|
||||
"slug": "if-any-assignments",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const items = state.steps['find-assigned-items'].output;\n return items && items.length > 0;\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "expire-assignments" }]
|
||||
},
|
||||
{
|
||||
"name": "Expire each assignment",
|
||||
"slug": "expire-assignments",
|
||||
"type": "PARALLEL_LOOP",
|
||||
"nodeSlug": "parallel-loop",
|
||||
"maxConcurrentIterations": 10,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "iterable",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['find-assigned-items'].output"
|
||||
}
|
||||
],
|
||||
"initialSteps": [
|
||||
{ "slug": "expire-one" }
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Expire single assignment",
|
||||
"slug": "expire-one",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"parentParallelLoopSlug": "expire-assignments",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation ExpireAssignation($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations {\n macAddress\n ipAddress\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const item = state.currentParallelLoopIterations['expire-assignments'];\n return {\n input: {\n assignations: {\n macAddress: item.macAddress,\n ipAddress: item.ipAddress,\n expired: true\n }\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
{ "slug": "expire-assignments-end" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
29
gaiia/clear_ips_step1_list.json
Normal file
29
gaiia/clear_ips_step1_list.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "Test - List IPs",
|
||||
"trigger": {
|
||||
"type": "MANUAL",
|
||||
"nextSteps": [{ "slug": "list" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "List assigned items",
|
||||
"slug": "list",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query { inventoryItems(filters: {assigneeType: {equals: ACCOUNT}}, first: 5) { totalCount } }"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ secrets, state, utils, variables }) => ({})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
27
gaiia/clear_ips_step2_expire_one.json
Normal file
27
gaiia/clear_ips_step2_expire_one.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "Test - Expire One IP",
|
||||
"description": "Bare minimum V0 expire test with hardcoded MAC+IP",
|
||||
"trigger": { "type": "MANUAL", "nextSteps": [{ "slug": "expire" }] },
|
||||
"steps": [
|
||||
{
|
||||
"name": "Expire",
|
||||
"slug": "expire",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation ExpireOne($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "LITERAL",
|
||||
"value": "json:{\"input\":{\"assignations\":{\"macAddress\":\"DC:9F:DB:92:0D:AA\",\"ipAddress\":\"10.10.16.74\",\"expired\":true}}}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
249
gaiia/compare_pppoe.py
Normal file
249
gaiia/compare_pppoe.py
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
"""Compare PPPoE active sessions from climax MikroTik against Gaiia accounts.
|
||||
|
||||
Checks:
|
||||
1. Is the PPPoE username found as a Gaiia account?
|
||||
2. Does the Gaiia account's inventory item IP match the PPPoE IP?
|
||||
|
||||
Usage: cd /Users/graham/dev/network/gaiia && uv run python compare_pppoe.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
|
||||
from gaiia.client import GaiiaClient
|
||||
|
||||
# PPPoE active sessions from climax (2026-07-02)
|
||||
PPPOE_SESSIONS: list[dict[str, str]] = [
|
||||
{"name": "charlesboone", "address": "100.64.7.247", "mac": "C8:9E:43:E3:99:EA"},
|
||||
{"name": "amberprater", "address": "100.64.7.243", "mac": "6C:CD:D6:2C:31:94"},
|
||||
{"name": "matthewgoodwin", "address": "100.64.7.241", "mac": "34:98:B5:44:42:A4"},
|
||||
{"name": "robbymccollom", "address": "100.64.7.239", "mac": "D8:B3:70:92:0C:C6"},
|
||||
{"name": "gordonhamilton", "address": "100.64.7.237", "mac": "A0:63:91:3A:29:B1"},
|
||||
{"name": "chasewilliams", "address": "100.64.7.235", "mac": "38:94:ED:5B:82:E9"},
|
||||
{"name": "cynthiajones", "address": "100.64.7.233", "mac": "E4:FA:C4:56:CA:D9"},
|
||||
{"name": "janicealexander", "address": "100.64.7.225", "mac": "E0:D3:62:E8:65:C5"},
|
||||
{"name": "michaelray", "address": "204.110.188.38", "mac": "9C:05:D6:59:FF:63"},
|
||||
{"name": "marysmelser", "address": "100.64.7.218", "mac": "00:01:9F:33:54:B9"},
|
||||
{"name": "eddieyarbrough", "address": "100.64.7.216", "mac": "10:C3:7B:42:D8:B8"},
|
||||
{"name": "timgilbert", "address": "100.64.7.213", "mac": "94:A6:7E:EE:98:B8"},
|
||||
{"name": "chadwhitsell", "address": "100.64.7.211", "mac": "04:95:E6:76:3C:91"},
|
||||
{"name": "donnacampbell", "address": "100.64.7.209", "mac": "74:FE:CE:3A:6D:AC"},
|
||||
{"name": "bryangoulart", "address": "100.64.7.205", "mac": "8C:90:2D:E9:90:7A"},
|
||||
{"name": "crystalharney", "address": "100.64.7.201", "mac": "98:25:4A:04:B6:43"},
|
||||
{"name": "johnvayo", "address": "100.64.7.197", "mac": "98:25:4A:04:B5:89"},
|
||||
{"name": "richardbarragan", "address": "100.64.7.193", "mac": "8C:90:2D:E9:98:E1"},
|
||||
{"name": "carolstrickland", "address": "100.64.7.189", "mac": "E8:DA:00:18:54:45"},
|
||||
{"name": "timbagert", "address": "100.64.7.140", "mac": "74:FE:CE:3A:6D:8E"},
|
||||
{"name": "douggarber", "address": "100.64.7.136", "mac": "00:01:9F:33:79:A9"},
|
||||
{"name": "janetkern", "address": "100.64.7.61", "mac": "28:C6:8E:C1:06:AF"},
|
||||
{"name": "gregmcintire", "address": "100.64.7.59", "mac": "66:62:8B:10:10:65"},
|
||||
{"name": "jenniferboon", "address": "100.64.7.35", "mac": "98:25:4A:04:BA:EA"},
|
||||
{"name": "glendabeauchamp", "address": "100.64.7.15", "mac": "8C:90:2D:E9:97:85"},
|
||||
{"name": "jmichaelculverhouse", "address": "100.64.7.250", "mac": "34:98:B5:31:D3:3A"},
|
||||
{"name": "elviraquezada", "address": "100.64.7.249", "mac": "E0:C2:50:47:DC:1A"},
|
||||
{"name": "tammieventris", "address": "100.64.7.232", "mac": "98:25:4A:04:A5:E1"},
|
||||
{"name": "taekim", "address": "204.110.188.42", "mac": "9C:5C:8E:44:85:B4"},
|
||||
{"name": "ruthfengler", "address": "100.64.7.246", "mac": "A0:63:91:25:F6:E5"},
|
||||
{"name": "buddyswan", "address": "100.64.7.245", "mac": "00:01:9F:34:D2:21"},
|
||||
{"name": "rhondabolton", "address": "100.64.7.231", "mac": "A0:04:60:94:D5:FF"},
|
||||
]
|
||||
|
||||
# Known PPPoE-name → Gaiia-displayName mismatches
|
||||
MANUAL_MAP: dict[str, str] = {
|
||||
"bryangoulart": "Brian Goulart", # typo in PPPoE username
|
||||
}
|
||||
|
||||
|
||||
def flatten(name: str) -> str:
|
||||
"""Lowercase and remove spaces/punctuation from a name."""
|
||||
return name.lower().replace(" ", "").replace("-", "").replace("'", "")
|
||||
|
||||
|
||||
def fetch_all_accounts(client: GaiiaClient) -> list[dict[str, Any]]:
|
||||
"""Fetch all Gaiia accounts (id, readableId, displayName)."""
|
||||
query = """
|
||||
query($after: String) {
|
||||
accounts(first: 50, after: $after) {
|
||||
nodes { id readableId displayName }
|
||||
pageInfo { hasNextPage endCursor }
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
"""
|
||||
accounts: list[dict[str, Any]] = []
|
||||
cursor: str | None = None
|
||||
has_next = True
|
||||
while has_next:
|
||||
variables: dict[str, Any] = {}
|
||||
if cursor:
|
||||
variables["after"] = cursor
|
||||
data = client.query(query, variables)
|
||||
conn = data["accounts"]
|
||||
accounts.extend(conn.get("nodes") or [])
|
||||
has_next = conn["pageInfo"]["hasNextPage"]
|
||||
cursor = conn["pageInfo"].get("endCursor")
|
||||
print(f" Fetched {len(accounts)}/{conn.get('totalCount', '?')} accounts...",
|
||||
file=sys.stderr)
|
||||
return accounts
|
||||
|
||||
|
||||
def fetch_account_inventory(
|
||||
client: GaiiaClient, account_id: str
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Fetch inventory items for a specific account, including IP addresses."""
|
||||
query = """
|
||||
query($id: GlobalID!) {
|
||||
account(id: $id) {
|
||||
assignedInventoryItems(first: 10) {
|
||||
nodes {
|
||||
inventoryItem {
|
||||
id
|
||||
ipAddressV4
|
||||
ipAddressV6
|
||||
model {
|
||||
name
|
||||
manufacturer { name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
data = client.query(query, {"id": account_id})
|
||||
acct = data.get("account")
|
||||
if not acct:
|
||||
return []
|
||||
items = acct.get("assignedInventoryItems", {})
|
||||
assignations = items.get("nodes") or []
|
||||
# Extract the actual inventory items from assignations
|
||||
result = []
|
||||
for assign in assignations:
|
||||
item = assign.get("inventoryItem")
|
||||
if item:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
|
||||
def main() -> None:
|
||||
api_key = os.environ.get("GAIIA_KEY")
|
||||
if not api_key:
|
||||
print("Error: GAIIA_KEY env var not set", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
client = GaiiaClient(api_key, timezone="America/Chicago")
|
||||
|
||||
print("Fetching all accounts from Gaiia...", file=sys.stderr)
|
||||
accounts = fetch_all_accounts(client)
|
||||
print(f"Total: {len(accounts)} accounts\n", file=sys.stderr)
|
||||
|
||||
# Build lookup: flattened displayName → account
|
||||
by_flat: dict[str, dict[str, Any]] = {}
|
||||
for a in accounts:
|
||||
by_flat[flatten(a.get("displayName", ""))] = a
|
||||
|
||||
# --- Step 1: Match PPPoE names to Gaiia accounts ---
|
||||
print("=" * 75)
|
||||
print("CLIMAX PPPoE → GAIIA ACCOUNT MATCHING")
|
||||
print("=" * 75)
|
||||
|
||||
matched: list[dict[str, Any]] = []
|
||||
unmatched: list[dict[str, Any]] = []
|
||||
|
||||
for session in PPPOE_SESSIONS:
|
||||
pname = session["name"]
|
||||
flat = flatten(pname)
|
||||
account = by_flat.get(flat)
|
||||
|
||||
# Try manual map
|
||||
if not account and pname in MANUAL_MAP:
|
||||
mapped_flat = flatten(MANUAL_MAP[pname])
|
||||
account = by_flat.get(mapped_flat)
|
||||
|
||||
session["_account"] = account
|
||||
if account:
|
||||
matched.append(session)
|
||||
else:
|
||||
unmatched.append(session)
|
||||
|
||||
print(f"{'PPPoE':<25} {'PPPoE IP':<18} {'Gaiia Name':<25} {'Account ID':<8}")
|
||||
print("-" * 78)
|
||||
for s in matched:
|
||||
acc = s["_account"]
|
||||
print(f"{s['name']:<25} {s['address']:<18} {acc['displayName']:<25} {acc['readableId']:<8}")
|
||||
for s in unmatched:
|
||||
print(f"{s['name']:<25} {s['address']:<18} {'(not in Gaiia)':<25} {'-':<8}")
|
||||
|
||||
print(f"\nMatched: {len(matched)} | Not in Gaiia: {len(unmatched)}")
|
||||
if unmatched:
|
||||
print("Not in Gaiia:")
|
||||
for s in unmatched:
|
||||
print(f" - {s['name']} ({s['address']})")
|
||||
|
||||
# --- Step 2: Compare IP addresses from inventory items ---
|
||||
print(f"\n{'=' * 75}")
|
||||
print("IP ADDRESS COMPARISON (PPPoE active IP vs Gaiia inventory item IP)")
|
||||
print("=" * 75)
|
||||
|
||||
ip_matched = 0
|
||||
ip_mismatched = 0
|
||||
ip_no_inventory = 0
|
||||
ip_not_checked = 0
|
||||
|
||||
for s in matched:
|
||||
acc = s["_account"]
|
||||
pppoe_ip = s["address"]
|
||||
pppoe_name = s["name"]
|
||||
|
||||
# Fetch inventory items for this account
|
||||
items = fetch_account_inventory(client, acc["id"])
|
||||
s["_items"] = items
|
||||
|
||||
if not items:
|
||||
print(f"{pppoe_name:<25} {pppoe_ip:<18} (no inventory items in Gaiia)")
|
||||
ip_no_inventory += 1
|
||||
continue
|
||||
|
||||
# Check if any inventory item has an IP matching the PPPoE IP
|
||||
found_match = False
|
||||
for item in items:
|
||||
item_ip = item.get("ipAddressV4")
|
||||
if item_ip == pppoe_ip:
|
||||
model = item.get("model", {})
|
||||
model_name = model.get("name", "?") if model else "?"
|
||||
print(f"{pppoe_name:<25} {pppoe_ip:<18} MATCH (item: {model_name})")
|
||||
ip_matched += 1
|
||||
found_match = True
|
||||
break
|
||||
|
||||
if not found_match:
|
||||
item_ips = [i.get("ipAddressV4") for i in items if i.get("ipAddressV4")]
|
||||
if item_ips:
|
||||
print(f"{pppoe_name:<25} {pppoe_ip:<18} MISMATCH (Gaiia has: {', '.join(item_ips)})")
|
||||
ip_mismatched += 1
|
||||
else:
|
||||
print(f"{pppoe_name:<25} {pppoe_ip:<18} NO IP SET (has inventory items but no IPs)")
|
||||
ip_no_inventory += 1
|
||||
|
||||
print(f"\n--- Summary ---")
|
||||
print(f"Accounts in Gaiia: {len(matched)}/{len(PPPOE_SESSIONS)}")
|
||||
print(f"Not in Gaiia: {len(unmatched)}")
|
||||
print(f"IP matches PPPoE: {ip_matched}")
|
||||
print(f"IP mismatch (different IP): {ip_mismatched}")
|
||||
print(f"No inventory / no IP in Gaiia: {ip_no_inventory}")
|
||||
|
||||
if unmatched:
|
||||
print(f"\nAccounts missing from Gaiia (need investigation):")
|
||||
for s in unmatched:
|
||||
mac = s.get("mac", "")
|
||||
print(f" {s['name']} IP={s['address']} MAC={mac}")
|
||||
|
||||
client.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
83
gaiia/daily_preseem_sync_workflow.json
Normal file
83
gaiia/daily_preseem_sync_workflow.json
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"name": "Daily Preseem Site Inventory Sync",
|
||||
"description": "SCHEDULED (daily 3am): Iterates all network sites, extracts MACs from assigned equipment fields, syncs each item to Preseem access points with its site name as tower.",
|
||||
"trigger": {
|
||||
"type": "SCHEDULE",
|
||||
"cron": "0 3 * * *",
|
||||
"nextSteps": [{ "slug": "fetch-sites" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Fetch all network sites with assigned equipment",
|
||||
"slug": "fetch-sites",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const sites = output.response.networkSites.nodes;\n const items = [];\n for (const site of sites) {\n for (const assign of (site.assignedInventoryItems?.nodes || [])) {\n const inv = assign.inventoryItem || {};\n const model = inv.model?.name || '';\n // Extract MAC from any field whose name contains 'mac' (case-insensitive)\n const macs = [];\n for (const f of (inv.fields?.nodes || [])) {\n const fieldName = (f.modelField?.name || '').toLowerCase();\n const data = (f.data || '').trim();\n if (fieldName.includes('mac') && data && data !== '00:00:00:00:00:00') {\n // Normalize MAC: strip '1:' prefix, pad segments, uppercase\n const cleaned = data.startsWith('1:') ? data.slice(2) : data;\n const parts = cleaned.split(':');\n if (parts.length === 6) {\n const normalized = parts\n .map((p) => p.padStart(2, '0').toUpperCase())\n .join(':');\n macs.push(normalized);\n }\n }\n }\n if (macs.length > 0) {\n items.push({\n inventoryId: inv.id,\n model,\n siteName: site.name,\n macs: [...new Set(macs)]\n });\n }\n }\n }\n return items;\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query {\n networkSites(first: 250) {\n nodes {\n id\n name\n assignedInventoryItems {\n nodes {\n inventoryItem {\n id\n model { name }\n ipAddressV4\n fields {\n nodes { data modelField { name } }\n }\n }\n }\n }\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ secrets, state, utils, variables }) => ({})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "if-any-items" }]
|
||||
},
|
||||
{
|
||||
"name": "Any items to sync?",
|
||||
"slug": "if-any-items",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const items = state.steps['fetch-sites'].output;\n return Array.isArray(items) && items.length > 0;\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "sync-to-preseem" }]
|
||||
},
|
||||
{
|
||||
"name": "Sync each item to Preseem",
|
||||
"slug": "sync-to-preseem",
|
||||
"type": "PARALLEL_LOOP",
|
||||
"nodeSlug": "parallel-loop",
|
||||
"maxConcurrentIterations": 10,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "iterable",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['fetch-sites'].output"
|
||||
}
|
||||
],
|
||||
"initialSteps": [{ "slug": "preseem-put-ap" }],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "PUT to Preseem access points",
|
||||
"slug": "preseem-put-ap",
|
||||
"type": "PRESEEM_REST_REQUEST",
|
||||
"nodeSlug": "preseem-rest-request",
|
||||
"parentParallelLoopSlug": "sync-to-preseem",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "method",
|
||||
"type": "LITERAL",
|
||||
"value": "string:PUT"
|
||||
},
|
||||
{
|
||||
"key": "path",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const item = state.currentParallelLoopIterations['sync-to-preseem'];\n return `/access_points/${item.inventoryId}`;\n}"
|
||||
},
|
||||
{
|
||||
"key": "body",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const item = state.currentParallelLoopIterations['sync-to-preseem'];\n return {\n id: item.inventoryId,\n name: `${item.model} (${item.macs[0]})`,\n tower: item.siteName\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "sync-to-preseem-end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
227
gaiia/dhcp_opt82_workflow.json
Normal file
227
gaiia/dhcp_opt82_workflow.json
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
{
|
||||
"name": "DHCP Option 82 Auth",
|
||||
"description": "WEBHOOK: Always upserts IP. If Option 82 present AND MAC linked to an account, syncs all inventoried MACs to Preseem with plan details.",
|
||||
"trigger": {
|
||||
"type": "WEBHOOK",
|
||||
"inputJsonSchema": {
|
||||
"type": "object",
|
||||
"required": ["bound", "mac", "ip", "server", "remoteId"],
|
||||
"properties": {
|
||||
"bound": { "type": "string" },
|
||||
"mac": { "type": "string" },
|
||||
"ip": { "type": "string" },
|
||||
"server": { "type": "string" },
|
||||
"remoteId": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"nextSteps": [{ "slug": "check-inventory" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Find inventory item by MAC",
|
||||
"slug": "check-inventory",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output, state }) => {\n const items = output.response.findInventoryItemsFromDeviceIdentifiers;\n // Accept items assigned to Accounts OR NetworkSites\n const assigned = items.filter(\n (item) => {\n const type = item.inventoryItem?.assignation?.assignee?.__typename;\n return type === 'Account' || type === 'NetworkSite';\n }\n );\n if (assigned.length === 0) return null;\n const inv = assigned[0].inventoryItem;\n const assignee = inv.assignation.assignee;\n return {\n assigneeId: assignee.id,\n assigneeType: assignee.__typename,\n assigneeName: assignee.name || ''\n };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query FindItem($input: FindInventoryItemsFromDeviceIdentifiersQueryInput!) {\n findInventoryItemsFromDeviceIdentifiers(input: $input) {\n identifier\n inventoryItem {\n id\n model { name }\n assignation {\n assignee {\n __typename\n ... on Account { id name }\n }\n }\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.mac;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return { input: { identifiers: [formattedMac] } };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "is-connect" }]
|
||||
},
|
||||
{
|
||||
"name": "Connect or disconnect?",
|
||||
"slug": "is-connect",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n return state.input.bound === '1';\n}",
|
||||
"elseSteps": [{ "slug": "expire-ip" }],
|
||||
"thenSteps": [{ "slug": "has-account-connect" }]
|
||||
},
|
||||
{
|
||||
"name": "Account found? (connect)",
|
||||
"slug": "has-account-connect",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n return state.steps['check-inventory'].output != null;\n}",
|
||||
"elseSteps": [{ "slug": "upsert-ip-no-account" }],
|
||||
"thenSteps": [{ "slug": "upsert-ip-with-account" }]
|
||||
},
|
||||
{
|
||||
"name": "Upsert IP (no account)",
|
||||
"slug": "upsert-ip-no-account",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation UpsertIp($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.mac;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return {\n input: {\n assignations: { macAddress: formattedMac, ipAddress: state.input.ip, expired: false }\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Upsert IP (with account)",
|
||||
"slug": "upsert-ip-with-account",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation UpsertIp($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.mac;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return {\n input: {\n assignations: { macAddress: formattedMac, ipAddress: state.input.ip, expired: false }\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "should-sync-preseem" }]
|
||||
},
|
||||
{
|
||||
"name": "Has Option 82 and account?",
|
||||
"slug": "should-sync-preseem",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const inv = state.steps['check-inventory'].output;\n if (inv == null) return false;\n if (!state.input.remoteId || state.input.remoteId === '') return false;\n return inv.assigneeType === 'Account';\n}",
|
||||
"elseSteps": [{ "slug": "should-sync-site" }],
|
||||
"thenSteps": [{ "slug": "get-account-macs-and-plan" }]
|
||||
},
|
||||
{
|
||||
"name": "Get all inventoried MACs and plan",
|
||||
"slug": "get-account-macs-and-plan",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output, state }) => {\n const account = output.response.account;\n if (!account) {\n workflow.fail('Account not found', 'ACCOUNT_NOT_FOUND');\n }\n const macs = [];\n for (const assign of (account.assignedInventoryItems?.nodes || [])) {\n const inv = assign.inventoryItem || {};\n for (const f of (inv.fields?.nodes || [])) {\n const fieldName = (f.modelField?.name || '').toLowerCase();\n const data = (f.data || '').trim();\n if (fieldName.includes('mac') && data && data !== '00:00:00:00:00:00') {\n const cleaned = data.startsWith('1:') ? data.slice(2) : data;\n const parts = cleaned.split(':');\n if (parts.length === 6) {\n macs.push(parts.map((p) => p.padStart(2, '0').toUpperCase()).join(':'));\n }\n }\n }\n for (const a of (inv.ipAddressAssignments?.nodes || [])) {\n if (a.macAddress) macs.push(a.macAddress.toUpperCase());\n }\n }\n const plan = (account.billingSubscriptions?.nodes || [])\n .map((s) => s.productVersion?.product?.slug)\n .find(Boolean) || '';\n return { macs: [...new Set(macs)], plan, gaiiaId: account.readableId };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const accountId = state.steps['check-inventory'].output.accountId;\n return `query { account(id: \"${accountId}\") { readableId assignedInventoryItems { nodes { inventoryItem { fields { nodes { data modelField { name } } } ipAddressAssignments { nodes { macAddress } } } } } billingSubscriptions { nodes { productVersion { product { slug } } } } } }`;\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => ({})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "preseem-update" }]
|
||||
},
|
||||
{
|
||||
"name": "Update Preseem",
|
||||
"slug": "preseem-update",
|
||||
"type": "PRESEEM_REST_REQUEST",
|
||||
"nodeSlug": "preseem-rest-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "method",
|
||||
"type": "LITERAL",
|
||||
"value": "string:PUT"
|
||||
},
|
||||
{
|
||||
"key": "path",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { gaiiaId } = state.steps['get-account-macs-and-plan'].output;\n return `/services/${gaiiaId}`;\n}"
|
||||
},
|
||||
{
|
||||
"key": "body",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { gaiiaId, macs, plan } = state.steps['get-account-macs-and-plan'].output;\n const rawMac = state.input.mac;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const connectingMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toLowerCase();\n const framedIp = state.input.ip;\n const inventoriedMacs = macs.map((m) => m.toLowerCase());\n const attachments = inventoriedMacs\n .filter((m) => state.input.bound === '0' || m !== connectingMac)\n .map((m) => ({ cpe_mac: m }));\n if (state.input.bound === '1') {\n attachments.push({ cpe_mac: connectingMac, network_prefixes: [framedIp] });\n }\n return {\n id: String(gaiiaId),\n attachments,\n account: String(gaiiaId),\n package: plan\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Expire IP",
|
||||
"slug": "expire-ip",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation ExpireIp($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.mac;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return {\n input: {\n assignations: { macAddress: formattedMac, ipAddress: state.input.ip, expired: true }\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "should-sync-preseem-disconnect" }]
|
||||
},
|
||||
{
|
||||
"name": "Network site with Option 82?",
|
||||
"slug": "should-sync-site",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const inv = state.steps['check-inventory'].output;\n if (inv == null) return false;\n if (!state.input.remoteId || state.input.remoteId === '') return false;\n return inv.assigneeType === 'NetworkSite';\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "preseem-site-update" }]
|
||||
},
|
||||
{
|
||||
"name": "Update Preseem (site)",
|
||||
"slug": "preseem-site-update",
|
||||
"type": "PRESEEM_REST_REQUEST",
|
||||
"nodeSlug": "preseem-rest-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "method",
|
||||
"type": "LITERAL",
|
||||
"value": "string:PUT"
|
||||
},
|
||||
{
|
||||
"key": "path",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const inv = state.steps['check-inventory'].output;\n return `/access_points/${inv.assigneeId}`;\n}"
|
||||
},
|
||||
{
|
||||
"key": "body",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const inv = state.steps['check-inventory'].output;\n const rawMac = state.input.mac;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const mac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toLowerCase();\n return {\n id: inv.assigneeId,\n name: inv.assigneeName || inv.assigneeId,\n tower: inv.assigneeName || '',\n ip_address: state.input.ip\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Has Option 82 and account? (disconnect)",
|
||||
"slug": "should-sync-preseem-disconnect",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const inv = state.steps['check-inventory'].output;\n if (inv == null) return false;\n if (!state.input.remoteId || state.input.remoteId === '') return false;\n return inv.assigneeType === 'Account';\n}",
|
||||
"elseSteps": [{ "slug": "should-sync-site-disconnect" }],
|
||||
"thenSteps": [{ "slug": "get-account-macs-and-plan" }]
|
||||
},
|
||||
{
|
||||
"name": "Network site? (disconnect)",
|
||||
"slug": "should-sync-site-disconnect",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const inv = state.steps['check-inventory'].output;\n if (inv == null) return false;\n if (!state.input.remoteId || state.input.remoteId === '') return false;\n return inv.assigneeType === 'NetworkSite';\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "preseem-site-update" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
39
gaiia/examples/basic.py
Normal file
39
gaiia/examples/basic.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
"""Minimal usage example.
|
||||
|
||||
Set GAIIA_KEY in your env, then ``python examples/basic.py``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from gaiia import GaiiaClient
|
||||
|
||||
|
||||
def main() -> None:
|
||||
with GaiiaClient(timezone="America/Chicago") as g:
|
||||
techs = g.query("{ technicians(first: 5) { nodes { id readableId firstName lastName } } }")
|
||||
for t in techs["technicians"]["nodes"]:
|
||||
print(f"{t['readableId']:>4} {t['firstName']} {t['lastName']} {t['id']}")
|
||||
|
||||
print("rate-limit:", g.last_rate_limit)
|
||||
|
||||
print("\npaginating all technicians:")
|
||||
for t in g.iter_nodes(
|
||||
"""
|
||||
query Q($after: String) {
|
||||
technicians(first: 50, after: $after) {
|
||||
nodes { id readableId firstName lastName }
|
||||
pageInfo { hasNextPage endCursor }
|
||||
}
|
||||
}
|
||||
""",
|
||||
"technicians",
|
||||
):
|
||||
print(f" {t['readableId']:>4} {t['firstName']} {t['lastName']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not os.environ.get("GAIIA_KEY"):
|
||||
raise SystemExit("Set GAIIA_KEY in your env first.")
|
||||
main()
|
||||
34
gaiia/examples/webhook_flask.py
Normal file
34
gaiia/examples/webhook_flask.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"""Verify gaiia webhooks in a Flask endpoint.
|
||||
|
||||
pip install flask gaiia
|
||||
GAIIA_WEBHOOK_SECRET=whsec_... flask --app examples/webhook_flask.py run
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from flask import Flask, abort, request
|
||||
|
||||
from gaiia import WebhookSignatureError, verify_webhook_signature
|
||||
|
||||
app = Flask(__name__)
|
||||
SECRET = os.environ["GAIIA_WEBHOOK_SECRET"]
|
||||
|
||||
|
||||
@app.post("/gaiia/webhook")
|
||||
def webhook() -> tuple[str, int]:
|
||||
raw = request.get_data()
|
||||
try:
|
||||
verify_webhook_signature(
|
||||
header_value=request.headers.get("X-Gaiia-Webhook-Signature", ""),
|
||||
raw_body=raw,
|
||||
secret=SECRET,
|
||||
)
|
||||
except WebhookSignatureError as e:
|
||||
abort(400, description=str(e))
|
||||
|
||||
event = json.loads(raw)
|
||||
app.logger.info("gaiia event: %s", event.get("type"))
|
||||
return "", 204
|
||||
37
gaiia/expire_one_workflow.json
Normal file
37
gaiia/expire_one_workflow.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "Expire Single IP Assignment",
|
||||
"trigger": {
|
||||
"type": "MANUAL",
|
||||
"inputJsonSchema": {
|
||||
"type": "object",
|
||||
"required": ["macAddress", "ipAddress"],
|
||||
"properties": {
|
||||
"macAddress": { "type": "string" },
|
||||
"ipAddress": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"nextSteps": [{ "slug": "expire" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Expire assignment",
|
||||
"slug": "expire",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation Expire($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => ({\n input: {\n assignations: {\n macAddress: state.input.macAddress,\n ipAddress: state.input.ipAddress,\n expired: true\n }\n }\n})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
307
gaiia/fuzzy_match.py
Normal file
307
gaiia/fuzzy_match.py
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Fuzzy match unmatched RADIUS users against Gaiia accounts.
|
||||
Smarter matching: requires first-name correlation when matching on last name,
|
||||
handles substring traps ("kim" in "kimberly"), etc.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from difflib import SequenceMatcher
|
||||
|
||||
GAIIA_KEY = "gaiia_sk_live_955b27e3680747a69ad40b403a912155_b0d1be3c"
|
||||
GAIIA_ENDPOINT = "https://api.gaiia.com/api/v1"
|
||||
|
||||
|
||||
def fetch_all_accounts():
|
||||
accounts = []
|
||||
cursor = None
|
||||
while True:
|
||||
after_arg = f', after: "{cursor}"' if cursor else ""
|
||||
query = f"""
|
||||
query {{
|
||||
accounts(first: 250{after_arg}) {{
|
||||
nodes {{ id readableId name displayName }}
|
||||
pageInfo {{ hasNextPage endCursor }}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["curl", "-s", "-X", "POST", GAIIA_ENDPOINT,
|
||||
"-H", "Content-Type: application/json",
|
||||
"-H", f"X-Gaiia-Api-Key: {GAIIA_KEY}",
|
||||
"-H", "x-timezone: America/Chicago",
|
||||
"-d", json.dumps({"query": query})],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
data = json.loads(result.stdout)
|
||||
for n in data["data"]["accounts"]["nodes"]:
|
||||
name = n.get("displayName") or n.get("name") or ""
|
||||
if name:
|
||||
accounts.append((n["id"], name.strip(), n["readableId"]))
|
||||
page_info = data["data"]["accounts"]["pageInfo"]
|
||||
if not page_info["hasNextPage"]:
|
||||
break
|
||||
cursor = page_info["endCursor"]
|
||||
return accounts
|
||||
|
||||
|
||||
def normalize(s):
|
||||
return re.sub(r'[^\w\s]', '', s.lower()).strip()
|
||||
|
||||
|
||||
def split_name(display_name):
|
||||
"""Split into first name(s) and last name."""
|
||||
parts = normalize(display_name).split()
|
||||
if len(parts) == 1:
|
||||
return parts[0], ""
|
||||
# Filter out suffixes, LLC, numbers, etc.
|
||||
content_parts = [p for p in parts if not re.match(r'^(#?\d+|llc|inc|ltd|shop|jr|sr)$', p)]
|
||||
if len(content_parts) >= 2:
|
||||
return " ".join(content_parts[:-1]), content_parts[-1]
|
||||
return content_parts[0], ""
|
||||
|
||||
|
||||
def first_name_match_score(username, last_name, first_name_str):
|
||||
"""How well does the first name correlate with the username? Returns 0-1.
|
||||
|
||||
The first initial must appear as the FIRST character of the username
|
||||
portion before the last name (natural "firstname+lastname" order).
|
||||
This prevents 'a' from "Amy" spuriously matching inside "ryan".
|
||||
"""
|
||||
if not first_name_str:
|
||||
return 0.5 # neutral
|
||||
|
||||
# Find where last name appears in username
|
||||
last_idx = username.find(last_name) if last_name else -1
|
||||
username_before_last = username[:last_idx] if last_idx > 0 else username
|
||||
|
||||
first_names = first_name_str.split()
|
||||
best = 0.0
|
||||
|
||||
for fn in first_names:
|
||||
if len(fn) < 2:
|
||||
continue
|
||||
fn_init = fn[0]
|
||||
if fn in username:
|
||||
return 1.0 # full first name in username
|
||||
# First initial must be the FIRST character before the last name
|
||||
if username_before_last and username_before_last[0] == fn_init:
|
||||
best = max(best, 0.7)
|
||||
# Fuzzy match
|
||||
ratio = SequenceMatcher(None, fn, username).ratio()
|
||||
best = max(best, ratio * 0.8)
|
||||
|
||||
return best
|
||||
|
||||
|
||||
def match_unmatched(unmatched_users, accounts):
|
||||
"""Fuzzy match with smarter scoring."""
|
||||
# Manual overrides from user knowledge
|
||||
MANUAL_MATCHES = {
|
||||
# (username, readable_id) -> forces match to specific Gaiia account
|
||||
"barbihardin": "James Hardin",
|
||||
"daycor": ("Cathy Day", 755),
|
||||
"tech": ("Graham McIntire", 1),
|
||||
# Add more as discovered
|
||||
}
|
||||
|
||||
# Build lookup by name
|
||||
accounts_by_name = {normalize(name): (aid, name, rid) for aid, name, rid in accounts}
|
||||
|
||||
results = []
|
||||
|
||||
for user in unmatched_users:
|
||||
username = user["username"].lower()
|
||||
username_no_digits = re.sub(r'\d+$', '', username)
|
||||
|
||||
# Check manual overrides first
|
||||
if username in MANUAL_MATCHES:
|
||||
override = MANUAL_MATCHES[username]
|
||||
# tuple form: (display_name, readable_id)
|
||||
if isinstance(override, tuple):
|
||||
target_name, target_rid = override
|
||||
for aid, name, rid in accounts:
|
||||
if normalize(name) == normalize(target_name) and rid == target_rid:
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": aid, "gaiia_name": name,
|
||||
"gaiia_readable_id": rid,
|
||||
"match_type": "fuzzy(manual_override)",
|
||||
})
|
||||
break
|
||||
else:
|
||||
# Fallback: match by name only
|
||||
norm_target = normalize(target_name)
|
||||
if norm_target in accounts_by_name:
|
||||
aid, name, rid = accounts_by_name[norm_target]
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": aid, "gaiia_name": name,
|
||||
"gaiia_readable_id": rid,
|
||||
"match_type": "fuzzy(manual_override)",
|
||||
})
|
||||
continue
|
||||
continue
|
||||
|
||||
# String form: match by name
|
||||
target_name = override
|
||||
norm_target = normalize(target_name)
|
||||
if norm_target in accounts_by_name:
|
||||
aid, name, rid = accounts_by_name[norm_target]
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": aid,
|
||||
"gaiia_name": name,
|
||||
"gaiia_readable_id": rid,
|
||||
"match_type": "fuzzy(manual_override)",
|
||||
})
|
||||
continue
|
||||
|
||||
best_match = None
|
||||
best_score = 0.0
|
||||
best_reason = ""
|
||||
|
||||
for acct_id, acct_name, readable_id in accounts:
|
||||
first_names, last_name = split_name(acct_name)
|
||||
aname = normalize(acct_name)
|
||||
aname_parts = aname.split()
|
||||
|
||||
score = 0.0
|
||||
reason = ""
|
||||
|
||||
# ---- Strategy 1: last name match + first name correlation ----
|
||||
if last_name and len(last_name) >= 3:
|
||||
# Check that last_name appears in username as a distinct substring
|
||||
# (not "kim" inside "kimberly")
|
||||
idx = username.find(last_name)
|
||||
if idx >= 0:
|
||||
# Check it's a reasonable boundary match
|
||||
# Allow: at start, at end, or surrounded by non-alpha
|
||||
before_ok = idx == 0 or not username[idx-1].isalpha()
|
||||
after_ok = (idx + len(last_name) == len(username)) or not username[idx+len(last_name)].isalpha()
|
||||
if not before_ok and not after_ok:
|
||||
# "kim" inside "kimberly" - reject this last name match
|
||||
pass
|
||||
else:
|
||||
# Check first name correlation
|
||||
fn_score = first_name_match_score(username, last_name, first_names)
|
||||
if fn_score >= 0.5:
|
||||
score = 0.7 + (fn_score * 0.2)
|
||||
reason = f"last+first: {last_name}+{first_names}(fn={fn_score:.2f})"
|
||||
elif fn_score > 0:
|
||||
score = 0.6 + fn_score * 0.1
|
||||
reason = f"last+weakfirst: {last_name}+{first_names}(fn={fn_score:.2f})"
|
||||
else:
|
||||
# Last name match but no first name correlation - low confidence
|
||||
score = 0.55
|
||||
reason = f"lastonly_nofirst: {last_name}"
|
||||
|
||||
# ---- Strategy 2: Sequence matcher on nodigits variant ----
|
||||
if score < 0.6 and username_no_digits != username:
|
||||
seq_score = SequenceMatcher(None, username_no_digits, aname).ratio()
|
||||
if seq_score > 0.75:
|
||||
score = max(score, seq_score * 0.9)
|
||||
reason = f"seq_nodigits: {seq_score:.2f}"
|
||||
|
||||
# ---- Strategy 3: Direct sequence match ----
|
||||
if score < 0.6:
|
||||
seq_score = SequenceMatcher(None, username, aname).ratio()
|
||||
if seq_score > 0.75:
|
||||
score = max(score, seq_score * 0.9)
|
||||
reason = f"sequence: {seq_score:.2f}"
|
||||
|
||||
# ---- Strategy 4: All account name parts in username ----
|
||||
if score < 0.6:
|
||||
all_found = True
|
||||
for part in aname_parts:
|
||||
if len(part) >= 3 and part not in username:
|
||||
all_found = False
|
||||
break
|
||||
if all_found and len(aname_parts) >= 2:
|
||||
score = 0.85
|
||||
reason = f"allparts: {aname}"
|
||||
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_match = (acct_id, acct_name, readable_id, score)
|
||||
best_reason = reason
|
||||
|
||||
# Threshold: 0.7+
|
||||
if best_match and best_score >= 0.7:
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": best_match[0],
|
||||
"gaiia_name": best_match[1],
|
||||
"gaiia_readable_id": best_match[2],
|
||||
"match_type": f"fuzzy({best_reason})",
|
||||
})
|
||||
else:
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": user.get("gaiia_id", ""),
|
||||
"gaiia_name": user.get("gaiia_name", ""),
|
||||
"gaiia_readable_id": user.get("gaiia_readable_id", ""),
|
||||
"match_type": f"still_unmatched(best: {best_reason}, score: {round(best_score,3)})",
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def resolve_ambiguous(ambiguous_rows, accounts):
|
||||
"""For ambiguous matches (duplicate Gaiia names), pick the lowest readable_id."""
|
||||
results = []
|
||||
for row in ambiguous_rows:
|
||||
ambig_names = row["gaiia_name"].replace("AMBIGUOUS: ", "").split(", ")
|
||||
candidates = [(a_id, name, r_id) for a_id, name, r_id in accounts if name in ambig_names]
|
||||
if candidates:
|
||||
candidates.sort(key=lambda x: x[2])
|
||||
row["gaiia_id"] = candidates[0][0]
|
||||
row["gaiia_name"] = candidates[0][1]
|
||||
row["gaiia_readable_id"] = candidates[0][2]
|
||||
row["match_type"] = "ambiguous_resolved(lowest_id)"
|
||||
else:
|
||||
row["match_type"] = "ambiguous_unresolved"
|
||||
results.append(row)
|
||||
return results
|
||||
|
||||
|
||||
def main():
|
||||
reader = csv.DictReader(sys.stdin)
|
||||
all_rows = list(reader)
|
||||
|
||||
unmatched = [r for r in all_rows if r["match_type"] == "no_match"]
|
||||
ambiguous = [r for r in all_rows if r["match_type"] == "ambiguous"]
|
||||
|
||||
print(f"Unmatched: {len(unmatched)}, Ambiguous: {len(ambiguous)}", file=sys.stderr)
|
||||
|
||||
print("Fetching Gaiia accounts...", file=sys.stderr)
|
||||
accounts = fetch_all_accounts()
|
||||
print(f"Fetched {len(accounts)} accounts", file=sys.stderr)
|
||||
|
||||
matched_results = match_unmatched(unmatched, accounts)
|
||||
ambig_results = resolve_ambiguous(ambiguous, accounts)
|
||||
|
||||
all_results = matched_results + ambig_results
|
||||
|
||||
fieldnames = ["radius_id", "username", "password", "gaiia_id", "gaiia_name", "gaiia_readable_id", "match_type"]
|
||||
writer = csv.DictWriter(sys.stdout, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
for r in all_results:
|
||||
writer.writerow({k: r.get(k, "") for k in fieldnames})
|
||||
|
||||
newly_matched = sum(1 for r in matched_results if r["gaiia_id"])
|
||||
still = sum(1 for r in matched_results if "still_unmatched" in r.get("match_type", ""))
|
||||
print(f"\nNewly matched: {newly_matched}, Still unmatched: {still}", file=sys.stderr)
|
||||
|
||||
print("\nStill unmatched:", file=sys.stderr)
|
||||
for r in matched_results:
|
||||
if "still_unmatched" in r.get("match_type", ""):
|
||||
print(f" {r['username']:30s} ({r['match_type']})", file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
438
gaiia/ip_assignments_page1.json
Normal file
438
gaiia/ip_assignments_page1.json
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
[
|
||||
{
|
||||
"macAddress": "DC:9F:DB:92:0D:AA",
|
||||
"ipAddress": "10.10.16.74"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:27:22:14:A7:F0",
|
||||
"ipAddress": "10.10.96.80"
|
||||
},
|
||||
{
|
||||
"macAddress": "DC:9F:DB:1E:D0:24",
|
||||
"ipAddress": "10.10.96.3"
|
||||
},
|
||||
{
|
||||
"macAddress": "04:18:D6:44:4A:46",
|
||||
"ipAddress": "10.10.96.56"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:27:22:14:2D:BB",
|
||||
"ipAddress": "10.10.96.76"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:61:07:7D",
|
||||
"ipAddress": "10.10.96.6"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:3B:D5:99",
|
||||
"ipAddress": "100.64.25.213"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:5C:A0:49",
|
||||
"ipAddress": "100.64.174.228"
|
||||
},
|
||||
{
|
||||
"macAddress": "E0:63:DA:90:74:76",
|
||||
"ipAddress": "10.10.96.96"
|
||||
},
|
||||
{
|
||||
"macAddress": "E0:63:DA:96:C1:3F",
|
||||
"ipAddress": "10.10.0.33"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:AC:B9:7A:17:9A",
|
||||
"ipAddress": "10.10.96.1"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:2F:D8:4D",
|
||||
"ipAddress": "10.10.128.10"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:AC:B9:7A:14:01",
|
||||
"ipAddress": "10.10.96.59"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:5C:A0:61",
|
||||
"ipAddress": "100.64.28.254"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:6B:0F:29",
|
||||
"ipAddress": "100.64.19.35"
|
||||
},
|
||||
{
|
||||
"macAddress": "FC:EC:DA:CE:68:19",
|
||||
"ipAddress": "10.10.16.70"
|
||||
},
|
||||
{
|
||||
"macAddress": "FC:EC:DA:CE:69:97",
|
||||
"ipAddress": "10.10.16.36"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:C2:87:DD",
|
||||
"ipAddress": "10.10.144.3"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:C1:BA:BE",
|
||||
"ipAddress": "10.10.128.5"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:FE:42:87",
|
||||
"ipAddress": "10.10.128.12"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:FE:31:A3",
|
||||
"ipAddress": "10.10.128.40"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:1E:9B:19",
|
||||
"ipAddress": "100.64.0.11"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:FE:47:0F",
|
||||
"ipAddress": "10.10.128.41"
|
||||
},
|
||||
{
|
||||
"macAddress": "18:E8:29:38:D3:45",
|
||||
"ipAddress": "10.10.16.48"
|
||||
},
|
||||
{
|
||||
"macAddress": "18:E8:29:38:D4:2C",
|
||||
"ipAddress": "10.10.16.69"
|
||||
},
|
||||
{
|
||||
"macAddress": "18:E8:29:38:D3:BC",
|
||||
"ipAddress": "10.10.0.11"
|
||||
},
|
||||
{
|
||||
"macAddress": "FC:EC:DA:6C:FD:08",
|
||||
"ipAddress": "10.10.96.68"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:83:C2:64:4A:22",
|
||||
"ipAddress": "10.10.16.72"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:83:C2:64:4A:B2",
|
||||
"ipAddress": "10.10.96.78"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:A0:56:B7",
|
||||
"ipAddress": "10.10.0.18"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:A0:56:0A",
|
||||
"ipAddress": "10.10.16.67"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:A0:57:88",
|
||||
"ipAddress": "10.10.0.13"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:A0:59:53",
|
||||
"ipAddress": "10.10.0.58"
|
||||
},
|
||||
{
|
||||
"macAddress": "D0:21:F9:AF:23:3E",
|
||||
"ipAddress": "10.10.62.200"
|
||||
},
|
||||
{
|
||||
"macAddress": "D0:21:F9:F0:9F:A4",
|
||||
"ipAddress": "10.10.62.203"
|
||||
},
|
||||
{
|
||||
"macAddress": "58:C1:7A:B3:09:72",
|
||||
"ipAddress": "10.10.16.59"
|
||||
},
|
||||
{
|
||||
"macAddress": "D0:21:F9:F0:9F:F4",
|
||||
"ipAddress": "10.10.62.215"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:AA:19:E6",
|
||||
"ipAddress": "10.10.0.15"
|
||||
},
|
||||
{
|
||||
"macAddress": "70:A7:41:4A:3C:55",
|
||||
"ipAddress": "10.10.160.12"
|
||||
},
|
||||
{
|
||||
"macAddress": "D0:21:F9:AF:23:02",
|
||||
"ipAddress": "10.10.62.202"
|
||||
},
|
||||
{
|
||||
"macAddress": "58:C1:7A:B3:08:B8",
|
||||
"ipAddress": "10.10.96.91"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:DB:7D:86",
|
||||
"ipAddress": "100.64.174.215"
|
||||
},
|
||||
{
|
||||
"macAddress": "E0:63:DA:0F:B7:8B",
|
||||
"ipAddress": "10.10.62.253"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:33:54:E9",
|
||||
"ipAddress": "100.64.25.32"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:AA:17:36",
|
||||
"ipAddress": "10.10.160.1"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:33:54:C1",
|
||||
"ipAddress": "100.64.0.221"
|
||||
},
|
||||
{
|
||||
"macAddress": "E4:38:83:AA:17:A6",
|
||||
"ipAddress": "10.10.160.4"
|
||||
},
|
||||
{
|
||||
"macAddress": "D0:21:F9:F0:9D:E1",
|
||||
"ipAddress": "10.10.62.212"
|
||||
},
|
||||
{
|
||||
"macAddress": "70:A7:41:4A:3C:3E",
|
||||
"ipAddress": "10.10.0.5"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:01:9F:34:D4:11",
|
||||
"ipAddress": "100.64.174.207"
|
||||
},
|
||||
{
|
||||
"macAddress": "D0:21:F9:F0:9F:32",
|
||||
"ipAddress": "10.10.62.201"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:DB:EC:AA",
|
||||
"ipAddress": "10.10.64.6"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:3E:1E",
|
||||
"ipAddress": "10.10.96.61"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:23:C5",
|
||||
"ipAddress": "10.10.0.8"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:2C:4E",
|
||||
"ipAddress": "10.10.96.12"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:28:40",
|
||||
"ipAddress": "10.10.96.20"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:35:33",
|
||||
"ipAddress": "10.10.0.1"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:3E:29",
|
||||
"ipAddress": "10.10.96.60"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:34:B5",
|
||||
"ipAddress": "10.10.96.25"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:3D:03",
|
||||
"ipAddress": "10.10.16.60"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:3D:E4",
|
||||
"ipAddress": "10.10.96.83"
|
||||
},
|
||||
{
|
||||
"macAddress": "F0:A7:31:74:A0:14",
|
||||
"ipAddress": "100.64.25.85"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:27:A5",
|
||||
"ipAddress": "10.10.0.2"
|
||||
},
|
||||
{
|
||||
"macAddress": "F0:A7:31:74:A0:4A",
|
||||
"ipAddress": "100.64.25.176"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:35:1D",
|
||||
"ipAddress": "10.10.96.69"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:31:14",
|
||||
"ipAddress": "10.10.0.24"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:2A:72",
|
||||
"ipAddress": "10.10.0.22"
|
||||
},
|
||||
{
|
||||
"macAddress": "E8:DA:00:17:B1:A9",
|
||||
"ipAddress": "100.64.174.203"
|
||||
},
|
||||
{
|
||||
"macAddress": "E8:DA:00:17:B1:E5",
|
||||
"ipAddress": "100.64.25.74"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:39:C0",
|
||||
"ipAddress": "10.10.0.70"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:2E:06",
|
||||
"ipAddress": "10.10.96.22"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:3F:F0",
|
||||
"ipAddress": "10.10.96.69"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:DB:EE:F3",
|
||||
"ipAddress": "10.10.160.5"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:29:CF",
|
||||
"ipAddress": "10.10.96.88"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:31:02",
|
||||
"ipAddress": "10.10.0.43"
|
||||
},
|
||||
{
|
||||
"macAddress": "70:A7:41:16:63:D1",
|
||||
"ipAddress": "10.10.96.71"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:31:ED",
|
||||
"ipAddress": "10.10.0.45"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:24:65",
|
||||
"ipAddress": "10.10.96.21"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:EF:9A:15",
|
||||
"ipAddress": "100.64.19.57"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:60:95:0D",
|
||||
"ipAddress": "10.10.144.9"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:60:8D:FB",
|
||||
"ipAddress": "10.10.64.6"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:F0:36:65",
|
||||
"ipAddress": "10.10.128.31"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:E8:3D:CF",
|
||||
"ipAddress": "10.10.144.28"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:FA:A6:49",
|
||||
"ipAddress": "10.10.128.39"
|
||||
},
|
||||
{
|
||||
"macAddress": "78:8A:20:3C:3B:4F",
|
||||
"ipAddress": "10.10.96.70"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:48:0E",
|
||||
"ipAddress": "10.10.0.39"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:4A:E6",
|
||||
"ipAddress": "10.10.96.63"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:47:E8",
|
||||
"ipAddress": "10.10.96.32"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:46:EA",
|
||||
"ipAddress": "10.10.0.52"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:4A:82",
|
||||
"ipAddress": "10.10.16.62"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:4B:56",
|
||||
"ipAddress": "10.10.0.51"
|
||||
},
|
||||
{
|
||||
"macAddress": "D8:44:89:A6:FF:01",
|
||||
"ipAddress": "100.64.25.97"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:4B:5E",
|
||||
"ipAddress": "10.10.16.54"
|
||||
},
|
||||
{
|
||||
"macAddress": "D8:44:89:A7:08:BB",
|
||||
"ipAddress": "100.64.25.55"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:E2:C6:30:3D:42",
|
||||
"ipAddress": "10.10.0.46"
|
||||
},
|
||||
{
|
||||
"macAddress": "D8:44:89:A7:0A:29",
|
||||
"ipAddress": "100.64.25.183"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:AC:B9:F2:08:EC",
|
||||
"ipAddress": "10.10.16.45"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:92:BF:D8:52:B0",
|
||||
"ipAddress": "10.10.0.10"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:AC:B9:F2:09:37",
|
||||
"ipAddress": "10.10.16.65"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:44:E0:32",
|
||||
"ipAddress": "10.10.144.37"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:44:F5:D7",
|
||||
"ipAddress": "10.10.96.16"
|
||||
},
|
||||
{
|
||||
"macAddress": "74:AC:B9:F2:08:5C",
|
||||
"ipAddress": "10.10.16.63"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:44:52:2D",
|
||||
"ipAddress": "10.10.128.23"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:2F:CD:D0",
|
||||
"ipAddress": "10.10.128.26"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:44:52:C6",
|
||||
"ipAddress": "10.10.96.27"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:2F:CD:16",
|
||||
"ipAddress": "10.10.16.39"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:2F:DB:53",
|
||||
"ipAddress": "10.10.128.7"
|
||||
},
|
||||
{
|
||||
"macAddress": "F4:92:BF:D8:55:4C",
|
||||
"ipAddress": "10.10.16.66"
|
||||
},
|
||||
{
|
||||
"macAddress": "00:04:56:44:F6:2E",
|
||||
"ipAddress": "10.10.128.29"
|
||||
}
|
||||
]
|
||||
68
gaiia/list_ip_assignments.py
Normal file
68
gaiia/list_ip_assignments.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python3
|
||||
"""List all customer inventory items with active IP assignments.
|
||||
Uses the Gaiia public API - run with GAIIA_KEY set (source .envrc)."""
|
||||
|
||||
from gaiia import GaiiaClient
|
||||
import json
|
||||
|
||||
def main():
|
||||
with GaiiaClient(timezone='America/Chicago') as g:
|
||||
# Paginate through all inventory items assigned to accounts
|
||||
all_assignments = []
|
||||
after = None
|
||||
page = 0
|
||||
|
||||
while True:
|
||||
page += 1
|
||||
query = """
|
||||
query GetAssignments($after: String) {
|
||||
inventoryItems(
|
||||
filters: {assigneeType: {equals: ACCOUNT}}
|
||||
first: 250
|
||||
after: $after
|
||||
) {
|
||||
nodes {
|
||||
ipAddressAssignments {
|
||||
nodes { ipAddress macAddress isActive }
|
||||
}
|
||||
}
|
||||
pageInfo { hasNextPage endCursor }
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
"""
|
||||
data = g.query(query, {"after": after} if after else {})
|
||||
result = data['inventoryItems']
|
||||
|
||||
if page == 1:
|
||||
print(f"Total inventory items assigned to accounts: {result['totalCount']}")
|
||||
|
||||
for item in result['nodes']:
|
||||
for a in item.get('ipAddressAssignments', {}).get('nodes', []):
|
||||
if a.get('isActive') != False: # active or None
|
||||
all_assignments.append({
|
||||
'macAddress': a['macAddress'],
|
||||
'ipAddress': a['ipAddress']
|
||||
})
|
||||
|
||||
page_info = result['pageInfo']
|
||||
if not page_info.get('hasNextPage'):
|
||||
break
|
||||
after = page_info['endCursor']
|
||||
|
||||
print(f"Active IP assignments found: {len(all_assignments)}")
|
||||
print()
|
||||
|
||||
# Print first 20
|
||||
for a in all_assignments[:20]:
|
||||
print(f" {a['macAddress']} -> {a['ipAddress']}")
|
||||
if len(all_assignments) > 20:
|
||||
print(f" ... and {len(all_assignments) - 20} more")
|
||||
|
||||
# Save to file
|
||||
with open('/Users/graham/dev/network/gaiia/ip_assignments.json', 'w') as f:
|
||||
json.dump(all_assignments, f, indent=2)
|
||||
print(f"\nSaved {len(all_assignments)} assignments to ip_assignments.json")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
202
gaiia/match_radius.py
Normal file
202
gaiia/match_radius.py
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Match RADIUS PPPoE usernames to Gaiia accounts by exact name-to-username mapping.
|
||||
Deterministic only — no fuzzy matching. Leaves ambiguous/unmatched rows blank.
|
||||
|
||||
A Gaiia displayName like "Jose Ortiz" generates candidate usernames:
|
||||
joseortiz, jortiz, joseo, jose, ortiz
|
||||
The RADIUS username must match one of these exactly.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
GAIIA_KEY = "gaiia_sk_live_955b27e3680747a69ad40b403a912155_b0d1be3c"
|
||||
GAIIA_ENDPOINT = "https://api.gaiia.com/api/v1"
|
||||
|
||||
|
||||
def fetch_all_accounts():
|
||||
"""Fetch all Gaiia accounts with id and displayName."""
|
||||
accounts = []
|
||||
cursor = None
|
||||
while True:
|
||||
after_arg = f', after: "{cursor}"' if cursor else ""
|
||||
query = f"""
|
||||
query {{
|
||||
accounts(first: 250{after_arg}) {{
|
||||
nodes {{ id readableId name displayName }}
|
||||
pageInfo {{ hasNextPage endCursor }}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
result = subprocess.run(
|
||||
[
|
||||
"curl", "-s",
|
||||
"-X", "POST", GAIIA_ENDPOINT,
|
||||
"-H", "Content-Type: application/json",
|
||||
"-H", f"X-Gaiia-Api-Key: {GAIIA_KEY}",
|
||||
"-H", "x-timezone: America/Chicago",
|
||||
"-d", json.dumps({"query": query}),
|
||||
],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
data = json.loads(result.stdout)
|
||||
nodes = data["data"]["accounts"]["nodes"]
|
||||
for n in nodes:
|
||||
name = n.get("displayName") or n.get("name") or ""
|
||||
if name:
|
||||
accounts.append((n["id"], name.strip(), n["readableId"]))
|
||||
page_info = data["data"]["accounts"]["pageInfo"]
|
||||
if not page_info["hasNextPage"]:
|
||||
break
|
||||
cursor = page_info["endCursor"]
|
||||
return accounts
|
||||
|
||||
|
||||
def generate_username_variants(display_name):
|
||||
"""Generate candidate PPPoE-style usernames from a Gaiia display name.
|
||||
|
||||
"Jose Ortiz" -> {joseortiz, jortiz, jose, ortiz}
|
||||
"Graham McIntire" -> {grahammcintire, gmcintire, graham, mcintire}
|
||||
"Kory Biggs Shop" -> {korybiggsshop, kbiggs, kory, biggs, ...}
|
||||
"Mid Valley Pumping LLC" -> {midvalleypumpingllc, midvalley, ...}
|
||||
"""
|
||||
name = display_name.lower().strip()
|
||||
# Remove punctuation
|
||||
name = re.sub(r'[^\w\s]', '', name)
|
||||
name = re.sub(r'\s+', ' ', name).strip()
|
||||
parts = name.split()
|
||||
|
||||
variants = set()
|
||||
|
||||
# Full concatenation: firstlast with no spaces
|
||||
variants.add("".join(parts))
|
||||
|
||||
# First initial + last name: e.g. jortiz, gmcintire
|
||||
if len(parts) >= 2:
|
||||
variants.add(parts[0][0] + parts[-1])
|
||||
# Also first name + last name initial
|
||||
variants.add(parts[0] + parts[-1][0])
|
||||
|
||||
# Each individual part
|
||||
for p in parts:
|
||||
variants.add(p)
|
||||
|
||||
# First + last (just the two parts concatenated)
|
||||
if len(parts) >= 2:
|
||||
variants.add(parts[0] + parts[-1])
|
||||
|
||||
# Handle numbered suffixes (e.g. "Perla Chavez 2" -> "perlachavez2")
|
||||
if len(parts) >= 3 and re.match(r'^\d+$', parts[-1]):
|
||||
variants.add("".join(parts[:-1]) + parts[-1])
|
||||
|
||||
return variants
|
||||
|
||||
|
||||
def parse_radius_input(text):
|
||||
"""Parse the pipe-delimited RADIUS user table."""
|
||||
users = []
|
||||
pattern = r'\|\s*(\d+)\s*\|\s*(\S+)\s*\|\s*Clear(?:t|T)ext-Password\s*\|\s*:=\s*\|\s*(\S+)\s*\|'
|
||||
for match in re.finditer(pattern, text):
|
||||
users.append({
|
||||
"radius_id": int(match.group(1)),
|
||||
"username": match.group(2),
|
||||
"password": match.group(3),
|
||||
})
|
||||
return users
|
||||
|
||||
|
||||
def match_users(radius_users, accounts):
|
||||
"""Match RADIUS users to Gaiia accounts by exact username variant matching."""
|
||||
# Build mapping: username_variant -> list of (account_id, account_name, readable_id)
|
||||
variant_map = defaultdict(list)
|
||||
for acct_id, acct_name, readable_id in accounts:
|
||||
for variant in generate_username_variants(acct_name):
|
||||
variant_map[variant].append((acct_id, acct_name, readable_id))
|
||||
|
||||
# Track which Gaiia accounts have been used (to avoid double-matching)
|
||||
used_accounts = set()
|
||||
|
||||
results = []
|
||||
for user in radius_users:
|
||||
username = user["username"].lower()
|
||||
candidates = variant_map.get(username, [])
|
||||
|
||||
# Filter out already-used accounts
|
||||
available = [(a, n, r) for a, n, r in candidates if a not in used_accounts]
|
||||
|
||||
if len(available) == 1:
|
||||
acct_id, acct_name, readable_id = available[0]
|
||||
used_accounts.add(acct_id)
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": acct_id,
|
||||
"gaiia_name": acct_name,
|
||||
"gaiia_readable_id": readable_id,
|
||||
"match_type": "exact",
|
||||
})
|
||||
elif len(available) > 1:
|
||||
# Multiple candidates — leave blank for manual review
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": "",
|
||||
"gaiia_name": f"AMBIGUOUS: {', '.join(n for _,n,_ in available)}",
|
||||
"gaiia_readable_id": "",
|
||||
"match_type": "ambiguous",
|
||||
})
|
||||
else:
|
||||
results.append({
|
||||
**user,
|
||||
"gaiia_id": "",
|
||||
"gaiia_name": "",
|
||||
"gaiia_readable_id": "",
|
||||
"match_type": "no_match",
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def main():
|
||||
text = sys.stdin.read()
|
||||
|
||||
radius_users = parse_radius_input(text)
|
||||
print(f"Parsed {len(radius_users)} RADIUS users", file=sys.stderr)
|
||||
|
||||
print("Fetching Gaiia accounts...", file=sys.stderr)
|
||||
accounts = fetch_all_accounts()
|
||||
print(f"Fetched {len(accounts)} Gaiia accounts with names", file=sys.stderr)
|
||||
|
||||
results = match_users(radius_users, accounts)
|
||||
|
||||
writer = csv.writer(sys.stdout)
|
||||
writer.writerow(["radius_id", "username", "password", "gaiia_id", "gaiia_name", "gaiia_readable_id", "match_type"])
|
||||
for r in results:
|
||||
writer.writerow([
|
||||
r["radius_id"], r["username"], r["password"],
|
||||
r["gaiia_id"], r["gaiia_name"], r["gaiia_readable_id"], r["match_type"],
|
||||
])
|
||||
|
||||
matched = sum(1 for r in results if r["gaiia_id"])
|
||||
ambiguous = sum(1 for r in results if r["match_type"] == "ambiguous")
|
||||
unmatched = sum(1 for r in results if r["match_type"] == "no_match")
|
||||
print(f"\nMatched: {matched}, Ambiguous: {ambiguous}, No match: {unmatched} (total: {len(results)})", file=sys.stderr)
|
||||
|
||||
if ambiguous:
|
||||
print("\nAMBIGUOUS (multiple Gaiia accounts match same username):", file=sys.stderr)
|
||||
for r in results:
|
||||
if r["match_type"] == "ambiguous":
|
||||
print(f" {r['username']}: {r['gaiia_name']}", file=sys.stderr)
|
||||
|
||||
if unmatched:
|
||||
print("\nNO MATCH:", file=sys.stderr)
|
||||
for r in results:
|
||||
if r["match_type"] == "no_match":
|
||||
print(f" {r['username']}", file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
101
gaiia/output.txt
Normal file
101
gaiia/output.txt
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
Fetching all accounts from Gaiia...
|
||||
Fetched 50/458 accounts...
|
||||
Fetched 100/458 accounts...
|
||||
Fetched 150/458 accounts...
|
||||
Fetched 200/458 accounts...
|
||||
Fetched 250/458 accounts...
|
||||
Fetched 300/458 accounts...
|
||||
Fetched 350/458 accounts...
|
||||
Fetched 400/458 accounts...
|
||||
Fetched 450/458 accounts...
|
||||
Fetched 458/458 accounts...
|
||||
Total: 458 accounts
|
||||
|
||||
===========================================================================
|
||||
CLIMAX PPPoE → GAIIA ACCOUNT MATCHING
|
||||
===========================================================================
|
||||
PPPoE PPPoE IP Gaiia Name Account ID
|
||||
------------------------------------------------------------------------------
|
||||
charlesboone 100.64.7.247 Charles Boone 62
|
||||
amberprater 100.64.7.243 Amber Prater 855
|
||||
matthewgoodwin 100.64.7.241 Matthew Goodwin 2453
|
||||
robbymccollom 100.64.7.239 Robby McCollom 297
|
||||
chasewilliams 100.64.7.235 Chase Williams 2042
|
||||
cynthiajones 100.64.7.233 Cynthia Jones 1778
|
||||
janicealexander 100.64.7.225 Janice Alexander 165
|
||||
michaelray 204.110.188.38 Michael Ray 379
|
||||
marysmelser 100.64.7.218 Mary Smelser 2385
|
||||
eddieyarbrough 100.64.7.216 Eddie Yarbrough 125
|
||||
timgilbert 100.64.7.213 Tim Gilbert 346
|
||||
chadwhitsell 100.64.7.211 Chad Whitsell 61
|
||||
donnacampbell 100.64.7.209 Donna Campbell 2530
|
||||
bryangoulart 100.64.7.205 Brian Goulart 2076
|
||||
crystalharney 100.64.7.201 Crystal Harney 2233
|
||||
johnvayo 100.64.7.197 John Vayo 2275
|
||||
richardbarragan 100.64.7.193 richard barragan 1314
|
||||
carolstrickland 100.64.7.189 Carol Strickland 2410
|
||||
timbagert 100.64.7.140 Tim Bagert 343
|
||||
douggarber 100.64.7.136 Doug Garber 2360
|
||||
janetkern 100.64.7.61 Janet Kern 449
|
||||
gregmcintire 100.64.7.59 Greg McIntire 380
|
||||
jenniferboon 100.64.7.35 Jennifer Boon 2200
|
||||
glendabeauchamp 100.64.7.15 Glenda Beauchamp 2133
|
||||
jmichaelculverhouse 100.64.7.250 J'michael Culverhouse 1838
|
||||
elviraquezada 100.64.7.249 Elvira Quezada 960
|
||||
taekim 204.110.188.42 Tae Kim 408
|
||||
ruthfengler 100.64.7.246 Ruth Fengler 304
|
||||
rhondabolton 100.64.7.231 Rhonda Bolton 295
|
||||
gordonhamilton 100.64.7.237 (not in Gaiia) -
|
||||
tammieventris 100.64.7.232 (not in Gaiia) -
|
||||
buddyswan 100.64.7.245 (not in Gaiia) -
|
||||
|
||||
Matched: 29 | Not in Gaiia: 3
|
||||
Not in Gaiia:
|
||||
- gordonhamilton (100.64.7.237)
|
||||
- tammieventris (100.64.7.232)
|
||||
- buddyswan (100.64.7.245)
|
||||
|
||||
===========================================================================
|
||||
IP ADDRESS COMPARISON (PPPoE active IP vs Gaiia inventory item IP)
|
||||
===========================================================================
|
||||
charlesboone 100.64.7.247 MISMATCH (Gaiia has: 10.10.16.73)
|
||||
amberprater 100.64.7.243 MISMATCH (Gaiia has: 10.10.16.56)
|
||||
matthewgoodwin 100.64.7.241 MISMATCH (Gaiia has: 10.10.16.34)
|
||||
robbymccollom 100.64.7.239 MISMATCH (Gaiia has: 10.10.16.69)
|
||||
chasewilliams 100.64.7.235 MISMATCH (Gaiia has: 10.10.16.66)
|
||||
cynthiajones 100.64.7.233 MISMATCH (Gaiia has: 10.10.16.72)
|
||||
janicealexander 100.64.7.225 MISMATCH (Gaiia has: 10.10.16.65)
|
||||
michaelray 204.110.188.38 (no inventory items in Gaiia)
|
||||
marysmelser 100.64.7.218 MATCH (item: AC1200MS)
|
||||
eddieyarbrough 100.64.7.216 NO IP SET (has inventory items but no IPs)
|
||||
timgilbert 100.64.7.213 MISMATCH (Gaiia has: 10.10.16.71)
|
||||
chadwhitsell 100.64.7.211 MISMATCH (Gaiia has: 10.10.16.75)
|
||||
donnacampbell 100.64.7.209 MATCH (item: AC1200-Mesh)
|
||||
bryangoulart 100.64.7.205 MISMATCH (Gaiia has: 10.10.16.62)
|
||||
crystalharney 100.64.7.201 MATCH (item: AC1200-Mesh)
|
||||
johnvayo 100.64.7.197 MATCH (item: AC1200-Mesh)
|
||||
richardbarragan 100.64.7.193 MATCH (item: AC1200-Mesh)
|
||||
carolstrickland 100.64.7.189 MISMATCH (Gaiia has: 10.10.16.37)
|
||||
timbagert 100.64.7.140 MATCH (item: AC1200-Mesh)
|
||||
douggarber 100.64.7.136 MISMATCH (Gaiia has: 10.10.16.57)
|
||||
janetkern 100.64.7.61 MISMATCH (Gaiia has: 10.10.16.54)
|
||||
gregmcintire 100.64.7.59 (no inventory items in Gaiia)
|
||||
jenniferboon 100.64.7.35 MATCH (item: AC1200-Mesh)
|
||||
glendabeauchamp 100.64.7.15 MATCH (item: AC1200-Mesh)
|
||||
jmichaelculverhouse 100.64.7.250 NO IP SET (has inventory items but no IPs)
|
||||
elviraquezada 100.64.7.249 MISMATCH (Gaiia has: 10.10.16.67)
|
||||
taekim 204.110.188.42 MISMATCH (Gaiia has: 10.10.16.70)
|
||||
ruthfengler 100.64.7.246 MISMATCH (Gaiia has: 10.10.16.46)
|
||||
rhondabolton 100.64.7.231 MISMATCH (Gaiia has: 10.10.16.61)
|
||||
|
||||
--- Summary ---
|
||||
Accounts in Gaiia: 29/32
|
||||
Not in Gaiia: 3
|
||||
IP matches PPPoE: 8
|
||||
IP mismatch (different IP): 17
|
||||
No inventory / no IP in Gaiia: 4
|
||||
|
||||
Accounts missing from Gaiia (need investigation):
|
||||
gordonhamilton IP=100.64.7.237 MAC=A0:63:91:3A:29:B1
|
||||
tammieventris IP=100.64.7.232 MAC=98:25:4A:04:A5:E1
|
||||
buddyswan IP=100.64.7.245 MAC=00:01:9F:34:D2:21
|
||||
198
gaiia/pppoe_full_sync_workflow.json
Normal file
198
gaiia/pppoe_full_sync_workflow.json
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
{
|
||||
"name": "pppoe auth",
|
||||
"description": "WEBHOOK: PPPoE connect/disconnect → account lookup → Preseem sync. Connect (bound=1): BYOD if needed, assign IP, add MAC to Preseem with all inventoried equipment. Disconnect (bound=0): remove MAC from Preseem.",
|
||||
"trigger": {
|
||||
"type": "WEBHOOK",
|
||||
"inputJsonSchema": {
|
||||
"type": "object",
|
||||
"required": ["bound", "callingstationid", "framedip", "username"],
|
||||
"properties": {
|
||||
"bound": { "type": "string" },
|
||||
"framedip": { "type": "string" },
|
||||
"username": { "type": "string" },
|
||||
"callingstationid": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"nextSteps": [{ "slug": "get-account-id" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Get Account ID from RADIUS Username",
|
||||
"slug": "get-account-id",
|
||||
"type": "CUSTOM_WORKFLOW",
|
||||
"nodeSlug": "get-account-id-from-radius-username",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{ "key": "username", "type": "STATE", "value": "input.username" }
|
||||
],
|
||||
"nextSteps": [{ "slug": "is-connect" }],
|
||||
"errorSteps": [{ "slug": "end", "errorCodes": ["USERNAME_NOT_FOUND"] }]
|
||||
},
|
||||
{
|
||||
"name": "Is this a connect?",
|
||||
"slug": "is-connect",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n return state.input.bound === '1';\n}",
|
||||
"elseSteps": [{ "slug": "expire-ip-assignment" }],
|
||||
"thenSteps": [{ "slug": "check-inventory" }]
|
||||
},
|
||||
{
|
||||
"name": "Expire IP assignment on disconnect",
|
||||
"slug": "expire-ip-assignment",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation ExpireIp($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.callingstationid;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return {\n input: {\n assignations: {\n macAddress: formattedMac,\n ipAddress: state.input.framedip,\n expired: true\n }\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "get-account-macs-and-plan" }]
|
||||
},
|
||||
{
|
||||
"name": "Check if MAC is already inventoried",
|
||||
"slug": "check-inventory",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output, state }) => {\n const items = output.response.findInventoryItemsFromDeviceIdentifiers;\n const assigned = items.filter(\n (item) => item.inventoryItem?.assignation?.assignee?.__typename === 'Account'\n );\n return assigned;\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query FindItem($input: FindInventoryItemsFromDeviceIdentifiersQueryInput!) {\n findInventoryItemsFromDeviceIdentifiers(input: $input) {\n identifier\n inventoryItem {\n id\n model { name }\n assignation {\n assignee {\n __typename\n ... on Account { id name }\n }\n }\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.callingstationid;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return { input: { identifiers: [formattedMac] } };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "if-byod-needed" }]
|
||||
},
|
||||
{
|
||||
"name": "Is BYOD needed?",
|
||||
"slug": "if-byod-needed",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const found = state.steps['check-inventory'].output;\n return !found || found.length === 0;\n}",
|
||||
"elseSteps": [{ "slug": "assign-ip-address" }],
|
||||
"thenSteps": [{ "slug": "find-byod-model" }]
|
||||
},
|
||||
{
|
||||
"name": "Find Customer Provided Router model",
|
||||
"slug": "find-byod-model",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const model = output.response.inventoryModels.nodes[0];\n if (!model) {\n workflow.fail('Customer Provided Router model not found', 'MODEL_NOT_FOUND');\n }\n const macField = model.fields.nodes.find(\n (field) => field.name === 'MAC Address'\n );\n if (!macField) {\n workflow.fail('MAC Address field not found on Customer Provided Router model', 'MAC_FIELD_NOT_FOUND');\n }\n return { id: model.id, macFieldId: macField.id };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query GetModel($filters: InventoryModelQueryFilters) {\n inventoryModels(filters: $filters) {\n nodes {\n id\n name\n fields { nodes { id name } }\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ secrets, state, utils, variables }) => {\n return { filters: { name: { equals: 'Customer Provided Router' } } };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "create-byod" }]
|
||||
},
|
||||
{
|
||||
"name": "Create BYOD inventory item",
|
||||
"slug": "create-byod",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation AddInventoryItems($input: CreateInventoryItemsInput!) {\n addInventoryItems(input: $input) {\n inventoryItemsCreationResult { addedItems { id } }\n errors { code message }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.callingstationid;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':');\n const accountId = state.steps['get-account-id'].output.accounts[0].accountId;\n const { id: modelId, macFieldId } = state.steps['find-byod-model'].output;\n return {\n input: {\n items: [{\n fields: [{ modelFieldId: macFieldId, data: formattedMac }],\n modelId: modelId,\n equipmentConditionType: 'NEW',\n purchasePriceInCents: 0,\n status: 'FUNCTIONAL',\n assignation: { assigneeId: accountId, assigneeType: 'ACCOUNT' }\n }]\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "assign-ip-address" }]
|
||||
},
|
||||
{
|
||||
"name": "Assign IP address to MAC",
|
||||
"slug": "assign-ip-address",
|
||||
"type": "GAIIA_API_GATEWAY_V0_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-internal-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:mutation UpsertIp($input: UpsertMacAddressIpAddressAssignationsInput!) {\n upsertMacAddressIpAddressAssignations(input: $input) {\n assignations { macAddress ipAddress }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const rawMac = state.input.callingstationid;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const formattedMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toUpperCase();\n return {\n input: {\n assignations: {\n macAddress: formattedMac,\n ipAddress: state.input.framedip,\n expired: false\n }\n }\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "get-account-macs-and-plan" }]
|
||||
},
|
||||
{
|
||||
"name": "Get all inventoried MACs and plan",
|
||||
"slug": "get-account-macs-and-plan",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output, state }) => {\n const account = output.response.account;\n if (!account) {\n workflow.fail('Account not found', 'ACCOUNT_NOT_FOUND');\n }\n const macs = [];\n for (const assign of (account.assignedInventoryItems?.nodes || [])) {\n const inv = assign.inventoryItem || {};\n for (const f of (inv.fields?.nodes || [])) {\n const fieldName = (f.modelField?.name || '').toLowerCase();\n const data = (f.data || '').trim();\n if (fieldName.includes('mac') && data && data !== '00:00:00:00:00:00') {\n const cleaned = data.startsWith('1:') ? data.slice(2) : data;\n const parts = cleaned.split(':');\n if (parts.length === 6) {\n macs.push(parts.map((p) => p.padStart(2, '0').toUpperCase()).join(':'));\n }\n }\n }\n for (const a of (inv.ipAddressAssignments?.nodes || [])) {\n if (a.macAddress) macs.push(a.macAddress.toUpperCase());\n }\n }\n const plan = (account.billingSubscriptions?.nodes || [])\n .map((s) => s.productVersion?.product?.slug)\n .find(Boolean) || '';\n return { macs: [...new Set(macs)], plan, gaiiaId: account.readableId };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const accountId = state.steps['get-account-id'].output.accounts[0].accountId;\n return `query { account(id: \"${accountId}\") { readableId assignedInventoryItems { nodes { inventoryItem { fields { nodes { data modelField { name } } } ipAddressAssignments { nodes { macAddress } } } } } billingSubscriptions { nodes { productVersion { product { slug } } } } } }`;\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => ({})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "preseem-update" }]
|
||||
},
|
||||
{
|
||||
"name": "Update Preseem",
|
||||
"slug": "preseem-update",
|
||||
"type": "PRESEEM_REST_REQUEST",
|
||||
"nodeSlug": "preseem-rest-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "method",
|
||||
"type": "LITERAL",
|
||||
"value": "string:PUT"
|
||||
},
|
||||
{
|
||||
"key": "path",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { gaiiaId } = state.steps['get-account-macs-and-plan'].output;\n return `/services/${gaiiaId}`;\n}"
|
||||
},
|
||||
{
|
||||
"key": "body",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { gaiiaId, macs, plan } = state.steps['get-account-macs-and-plan'].output;\n const rawMac = state.input.callingstationid;\n const cleanedMac = rawMac.startsWith('1:') ? rawMac.slice(2) : rawMac;\n const connectingMac = cleanedMac\n .split(':')\n .map((segment) => segment.padStart(2, '0'))\n .join(':')\n .toLowerCase();\n const framedIp = state.input.framedip;\n // On connect (bound=1): include connecting MAC with its IP. On disconnect (bound=0): exclude it.\n const inventoriedMacs = macs.map((m) => m.toLowerCase());\n const attachments = inventoriedMacs\n .filter((m) => state.input.bound === '0' || m !== connectingMac)\n .map((m) => ({ cpe_mac: m }));\n if (state.input.bound === '1') {\n attachments.push({ cpe_mac: connectingMac, network_prefixes: [framedIp] });\n }\n return {\n id: String(gaiiaId),\n attachments,\n account: String(gaiiaId),\n package: plan\n };\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
63
gaiia/pyproject.toml
Normal file
63
gaiia/pyproject.toml
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
[build-system]
|
||||
requires = ["hatchling>=1.18"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "gaiia"
|
||||
version = "0.1.0"
|
||||
description = "Python client for the gaiia GraphQL API and webhooks."
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
requires-python = ">=3.10"
|
||||
authors = [{ name = "Graham McIntire", email = "graham@mcintire.me" }]
|
||||
keywords = ["gaiia", "graphql", "api", "wisp", "isp", "client"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = ["httpx>=0.27"]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=8",
|
||||
"pytest-asyncio>=0.23",
|
||||
"respx>=0.21",
|
||||
"mypy>=1.10",
|
||||
"ruff>=0.5",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://app.gaiia.com/docs/overview"
|
||||
Documentation = "https://app.gaiia.com/docs/overview"
|
||||
Source = "https://github.com/grahammcintire/gaiia-py"
|
||||
Issues = "https://github.com/grahammcintire/gaiia-py/issues"
|
||||
|
||||
[tool.hatch.build.targets.sdist]
|
||||
include = ["src/gaiia", "README.md", "LICENSE"]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/gaiia"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py310"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "I", "B", "UP", "SIM"]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.10"
|
||||
strict = true
|
||||
warn_unused_ignores = true
|
||||
68
gaiia/radius_gaiia_fuzzy.csv
Normal file
68
gaiia/radius_gaiia_fuzzy.csv
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
radius_id,username,password,gaiia_id,gaiia_name,gaiia_readable_id,match_type
|
||||
29521,tiffanyyarley-olenak,98HTZ9Q8FARG,account_cwmjmXkrYeba8h8RGqLm6E,Tiffany Yarley-Olenak,2393,fuzzy(sequence: 0.95)
|
||||
29395,vanessagomez1,J5JEW3HEBVAF,account_gb82EhqTwbNWWEovPu4oKZ,Vanessa Gomez,2264,fuzzy(last+first: gomez+vanessa(fn=1.00))
|
||||
29611,brittannieredden1,TYFTUEZ7429,account_bB6RDmNpkzndVbSh9CvgaL,Brittannie Redden,10017,fuzzy(last+first: redden+brittannie(fn=1.00))
|
||||
29614,samanthatheis,kf6u8djigk,account_x46hMNq15qHmEvP6fNFdfm,Samatha Theis,10023,fuzzy(last+first: theis+samatha(fn=0.70))
|
||||
29216,wanxiaxong,BER4NEK9M7NA,account_tiy5YHD34KpwPzUTXyRVFJ,Wanxia Song,2077,fuzzy(sequence: 0.86)
|
||||
29215,bryangoulart,DTNQFE4CXSFX,account_9sksoKmcJGxqhz4M4aD169,Brian Goulart,2076,fuzzy(last+first: goulart+brian(fn=0.70))
|
||||
29602,tech,brussels-crucial-smashing,account_jUFnZ52urgAMNgp9XhT4bs,Graham McIntire,1,fuzzy(manual_override)
|
||||
28935,chrislewis1,V9DS4E4Y7UTT,account_osB3NhyGdoWJRtpL5X2bfD,chris lewis,1787,fuzzy(last+first: lewis+chris(fn=1.00))
|
||||
28917,crankkeith,kcrank10615,account_iSuzVkNmem52NdXXh1Savu,Keith Crank,209,fuzzy(last+first: crank+keith(fn=1.00))
|
||||
28703,grahammcintire2,U5Y3hA3g*14L,account_jUFnZ52urgAMNgp9XhT4bs,Graham McIntire,1,fuzzy(last+first: mcintire+graham(fn=1.00))
|
||||
28702,chrissyeagle2,NJPCGPBNFB,account_3uu7k4euycmKnZii9DQAj2,Chrissy Eagle,74,fuzzy(last+first: eagle+chrissy(fn=1.00))
|
||||
28671,melodymccarty,U3WLEGEB,account_18HG9hdwwtZM83J9kyGMs6,Melody McCarthy,1397,fuzzy(sequence: 0.93)
|
||||
28642,barbihardin,ZENETJ75TEVQ,account_bb7iRuPixxutKZxnURfK5U,James Hardin,1475,fuzzy(manual_override)
|
||||
28628,jackworthy,2VUR7AAFWZZQ,account_hgoipVYXydD1yVSXTD9QGP,John Worthy,1461,fuzzy(last+first: worthy+john(fn=0.70))
|
||||
28542,michaelray2,jjPgDcotL6rtY,account_8Rh7edwTjNBYw9FJSq4WRT,Michael Ray,379,fuzzy(last+first: ray+michael(fn=1.00))
|
||||
28458,kennethcampbell2,V5TKW8L6RXFF,account_jF69QnP5j9FtfLgdAiUKfE,Kenneth D. Campbell,213,fuzzy(last+first: campbell+kenneth d(fn=1.00))
|
||||
28296,cinthiapereira1,9WSGXM9LBXGZ,account_57mDq22QWRV8tdPvk74Uvj,Cinthia Pereira,1102,fuzzy(last+first: pereira+cinthia(fn=1.00))
|
||||
29531,daycor,U45YBPSARH7N,account_aZmcKqobMWGKhxagDdLCFA,Cathy Day,755,fuzzy(manual_override)
|
||||
29620,sayedahaque,YR4Sytbu,account_4hoTCjwTatthCg7zp2Cnfe,Syeda Haque,10048,fuzzy(last+first: haque+syeda(fn=0.70))
|
||||
27417,donniecampbell,6a2671bc0c1,account_4ww28eUsFRv8Yh5RkWe9cz,Danny Campbell,92,fuzzy(last+first: campbell+danny(fn=0.70))
|
||||
27418,alanwyatt,i1412r53MYr,account_2cnVCpSsYocCYpMEwwBBrY,Allen Wyatt,27,fuzzy(last+first: wyatt+allen(fn=0.70))
|
||||
27436,clayrobertson2,C2147288546R,account_jgtX7TysTqcobVVBtSZEc2,Clay Robertson,77,fuzzy(last+first: robertson+clay(fn=1.00))
|
||||
27501,jonnytaylor,Zb6677&4!yky,account_1fDruGS6CFTBUCGuzVZYTG,Johnny Taylor,190,fuzzy(last+first: taylor+johnny(fn=0.70))
|
||||
27579,donnance,9727346814,account_s9ZW1FpS3wkDoh31CjU1Zw,Dana Nance,89,fuzzy(last+first: nance+dana(fn=0.70))
|
||||
27838,consueloluna1830,C8736gfd0,account_jw16PcKtprHpPkSAEhvsaN,Consuelo Luna,81,fuzzy(last+first: luna+consuelo(fn=1.00))
|
||||
27912,blancadiaz,B548gdu55D,account_ktdNSpKRV3ja7RMi7pZRBB,Balnca Diaz,433,fuzzy(last+first: diaz+balnca(fn=0.70))
|
||||
27639,choonpang,CP2143855677cp,account_o7aKk2FGKJAcmrXxMfUCpX,Geok Choon Pang,146,fuzzy(last+first: pang+geok choon(fn=1.00))
|
||||
27618,tammieventris,DR45QC74M,account_fMQ6qiwkPFWP8a86exFw4A,Terry Ventris,340,fuzzy(last+first: ventris+terry(fn=0.70))
|
||||
27939,reynamoore,R92nbskba7iM,account_k8gD8YGUQzwWCE7JT9EfYc,Rebekah Moore,386,fuzzy(last+first: moore+rebekah(fn=0.70))
|
||||
27781,pambanschbach,Q2p68#*9vwF2,account_6hGXtJ7RV7mqZYfd5AyE1f,Pam Bansbach,383,fuzzy(sequence: 0.88)
|
||||
28107,jacquelinewilder,HEY36LUGYCUQ,account_hHa9Z64B9okZ3yccQP9WpR,Jacquelin Wilder,892,fuzzy(last+first: wilder+jacquelin(fn=1.00))
|
||||
29554,marcuspatton,GEUXX27VLZXK,account_dxY6AZnLdFUWup8Sf6XER1,Marcus Patton,2458,ambiguous_resolved(lowest_id)
|
||||
29606,mariacastanon,iu297gkid9,account_qh8bFPvWzyAqHqwHMDkThW,Maria Castanon,10007,ambiguous_resolved(lowest_id)
|
||||
28800,kennethcampbell,!9727342446!,account_jF69QnP5j9FtfLgdAiUKfE,Kenneth D. Campbell,213,ambiguous_resolved(lowest_id)
|
||||
28358,stephenday,MSVGQ8X38YLN,account_j1UFX8wqzorqSetUje5dTJ,Stephen Day,1168,ambiguous_resolved(lowest_id)
|
||||
29630,sriahobilamuth,RTCESW24,account_7PgSr8dVuafybJdrXND3V9,Sri Ahobilamuth,113,ambiguous_resolved(lowest_id)
|
||||
27404,grahammcintire,U5Y3hA3g*14L,account_jUFnZ52urgAMNgp9XhT4bs,Graham McIntire,1,ambiguous_resolved(lowest_id)
|
||||
29524,chandparvathaneni,TK4QA3XM5XK5,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29358,radiantlifeministries,12FDIUNF5L7vM,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29296,midvalleyconcrete,BD58JYT2PJ6A,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29244,janiscable,JHC7U554JBTR,,,,"still_unmatched(best: last+weakfirst: cable+gary w(fn=0.11), score: 0.611)"
|
||||
29150,donwilhelmus,2V4NEL87RM39,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29135,kavalleriefarm,8DFNNTPBPZGY,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29077,kellygarza,4696591662,,,,"still_unmatched(best: last+weakfirst: garza+esparanza(fn=0.42), score: 0.642)"
|
||||
29070,1stchoiceliving,YVWJWRPEVYNH,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28879,kimberlyrichards,7PQA6J8RPZ9Z,,,,"still_unmatched(best: last+weakfirst: kim+tae(fn=0.08), score: 0.608)"
|
||||
28599,ryanrodriguez,9DFYWJ47YWUP,,,,"still_unmatched(best: last+weakfirst: rodriguez+mike(fn=0.19), score: 0.619)"
|
||||
28460,saidaacosta,V29897X4,,,,"still_unmatched(best: last+weakfirst: acosta+alma(fn=0.21), score: 0.621)"
|
||||
28422,jackiehendricks,UQR5HGFCJ4XX,,,,"still_unmatched(best: last+weakfirst: hendricks+sue(fn=0.09), score: 0.609)"
|
||||
28400,bonniestone,BH8BV44TTWUU,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28336,buddyswan,N7XUYUD7J9SD,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28268,alberto,TICOGUILLO,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27408,penneywarner,b4h53N6c#5wo,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29626,karengreen,UTKCYI674,,,,"still_unmatched(best: last+weakfirst: green+dominique(fn=0.17), score: 0.617)"
|
||||
27441,samanthasmith,22jmR9X#93j5,,,,"still_unmatched(best: last+weakfirst: smith+kathy(fn=0.27), score: 0.627)"
|
||||
27489,jenniferreed,683P7V7R,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27482,irvinbarojas,yDeEJzYY08,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27463,dennispereyra,82s62kd9XHhd,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27709,sensibleheatsystems,SHQWERY23,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27704,lambandlion,LL9727363567ll,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27625,mattbud,kjklfda79sd,,,,"still_unmatched(best: , score: 0.0)"
|
||||
127621,richardhill,RH9729788124rh,,,,"still_unmatched(best: last+weakfirst: hill+ellen(fn=0.20), score: 0.62)"
|
||||
27955,evlynrichter,FRQD738BGRC,,,,"still_unmatched(best: last+weakfirst: richter+brent(fn=0.19), score: 0.619)"
|
||||
27755,gordonhamilton,c3495Rpuq5Sh,,,,"still_unmatched(best: last+weakfirst: hamilton+sheryl f(fn=0.16), score: 0.616)"
|
||||
27793,branchrvpark,XfKxVZIKmm,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29601,kimberlyrichards2,K84f7r10GT108,,,,"still_unmatched(best: last+weakfirst: kim+tae(fn=0.08), score: 0.608)"
|
||||
28213,krisdougherty,RWEH75UJ38,,,,"still_unmatched(best: , score: 0.0)"
|
||||
|
416
gaiia/radius_gaiia_matched.csv
Normal file
416
gaiia/radius_gaiia_matched.csv
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
radius_id,username,password,gaiia_id,gaiia_name,gaiia_readable_id,match_type
|
||||
29581,joseortiz,J2WEYT7782UJ,account_4jKF2XxS1tjfAiTJLsFcGJ,Jose Ortiz,2485,exact
|
||||
29578,perlachavez2,U4BBTBMCJZST,account_sSL9o2BAvbEHXAkxWtPXxV,Perla Chavez 2,2482,exact
|
||||
29575,thomashernandez,X6BZLA7SC3XM,account_wL9tsaty83QCJpNGNXeSzZ,Thomas Hernandez,2479,exact
|
||||
29572,williamarmstead,SAQ4XEKXDC58,account_5Eqdv89tv7SUwTjGqQWJdh,William Armstead,2476,exact
|
||||
29570,julierose,MLM8R2WAGY52,account_9hvebUFe6UDfaZb9omVkB8,Julie Rose,2474,exact
|
||||
29571,derrickmccausland,ETNLKZHACGF7,account_89xduFTiVvRoEQpENiaVmT,Derrick Mccausland,2475,exact
|
||||
29567,sherrifredrick,7P52BVMTSNN6,account_3eF55epzgGSPhDU1DFBm53,Sherri Fredrick,2471,exact
|
||||
29565,shelbyburris,3YAL9DWFZUPT,account_9GNShE9ayAX3fkjwSryGq7,Shelby Burris,2469,exact
|
||||
29564,priscillacrenshaw,AXBDLXSGXMLR,account_2MK9ykEGzWyxvg1SZMmagK,Priscilla Crenshaw,2468,exact
|
||||
29561,korybiggs,4FJC7DXAW5RV,account_ftDbZQGSaf8dowpdjC44sU,Kory Biggs,2465,exact
|
||||
29563,kristinjimenez,9FAYXMRDU69T,account_bdpYxupJ3cfQ5bmhNroy8i,Kristin Jimenez,2467,exact
|
||||
29558,jessicaweddle,VV96G36AEEDA,account_khW6HArsQ677gL18hcQnEN,Jessica Weddle,2462,exact
|
||||
29557,yolandamedrano,R948UL4KZRA4,account_4tZA9NMygTcq3fidSxDz5h,Yolanda Medrano,2461,exact
|
||||
29555,williambowland,K7HYNWGE25XX,account_6fhZdgAsyd9zJ2FiXURCJ2,William Bowland,2459,exact
|
||||
29553,shacaciabillings,8AZLJCDFYFYV,account_pDDXT9Lh8QsE2roPyeVfS8,Shacacia Billings,2457,exact
|
||||
29552,guadalupelugo,DQG8XCMFMVH5,account_haPf3cXEdK4TQMzqZi5LYV,Guadalupe Lugo,2456,exact
|
||||
29551,brandonhardesty,KMRHVPEXBEZ8,account_izj2Jd1nYA49rAcvNu6TfZ,Brandon Hardesty,2455,exact
|
||||
29550,nancyavellaneda,CXATYV7NGZN2,account_99jecysxoYGBHUhd97ZYmt,Nancy Avellaneda,2454,exact
|
||||
29549,matthewgoodwin,VSPM7N9UNU6Y,account_ocezHaQ4JPvu1EbRMk4hu5,Matthew Goodwin,2453,exact
|
||||
29545,donmckinney,C6AQ6UVD6R7R,account_viJJswZvVXEbxLBikRjGJz,Don Mckinney,2449,exact
|
||||
29544,natashaelmore,8G5QJ8R7MK8Q,account_bGYACsz7a5kdyDBDecBTZY,Natasha Elmore,2448,exact
|
||||
29543,shamsbashir,WLBGY4JMN4VA,account_vtGoVXJRkxWw3ZEYDKi9Bu,Shams Bashir,2415,exact
|
||||
29541,douglasglover,9Y6H9X3HCG3D,account_hzZvaSXgCuhMUTXjpaCQjA,Douglas Glover,2413,exact
|
||||
29538,carolstrickland,547P6AQ8RCD4,account_u8W2U31Z3LJgzNcD2qNfcX,Carol Strickland,2410,exact
|
||||
29537,carmenlopez,TPLND3H2FWTQ,account_75ZP8Rhk7DBvwEA83HaWBB,Carmen Lopez,2409,exact
|
||||
29534,johnlooper,ZPL8LRY2TGRH,account_iijdXYXJAhg1mDm1FRuUrc,John Looper,2406,exact
|
||||
29535,davidroesch,ZHB2BS968DTU,account_bHVKB5E3eJFmbqnDwXAxFw,David Roesch,2407,exact
|
||||
29530,derekrodriguez,AP7Z594DMR7E,account_8MmcYW5A3KpMsyBJjiQMfE,Derek Rodriguez,2402,exact
|
||||
29522,joshuasoliz,PE7MHRZWUEQM,account_fPwqeAaDrYSWtRyVjBk8HD,Joshua Soliz,2394,exact
|
||||
29514,ericbarrett,5S2CV9FEFMKG,account_fhkdvYwigwTL9hR4Stx8Tf,Eric Barrett,2386,exact
|
||||
29513,marysmelser,ZS74NS5BBPX3,account_sN8UFBKJy6HHSCXSQp8oTB,Mary Smelser,2385,exact
|
||||
29506,nicolemaenn,B7KS27WL5WSN,account_pJFWGZXwDitJCT55tcuqeE,Nicole Maenn,2378,exact
|
||||
29503,yolandajudge,6V8RLNK75LM8,account_cWR4qvSM1SepG3DuoD8rUz,Yolanda Judge,2375,exact
|
||||
29501,craighovde,AVZXWBX8GQTC,account_q9j2WgU1236uDnx5rrEx8U,Craig Hovde,2373,exact
|
||||
29498,joselucas,ZHMW9TE8QHRX,account_izByTUMCPK7UT8k6Zncc4e,Jose Lucas,2370,exact
|
||||
29488,douggarber,WXP9J5SRJWEJ,account_vyxx47PALJmyUZZe3m495N,Doug Garber,2360,exact
|
||||
29482,carmencleghorn,VH3CBTJZAJ2Y,account_cRZQwgdsQLcok1dzXy6U5c,Carmen Cleghorn,2354,exact
|
||||
29472,rubenreyez,66384Y7B4WR4,account_aC929RXGkB1nsEHu95kg5v,Ruben Reyez,2344,exact
|
||||
29464,tiffanystewart,3EGVCS6RMF3Z,account_h3oACsArSoq5fZ6vRyH9Br,Tiffany Stewart,2335,exact
|
||||
29449,dejadodson,FLR4DJHPX6TG,account_57jxCEcSpkMPUEVxDoZddc,Deja Dodson,2320,exact
|
||||
29447,coreyball,3JAUWZNAR9MB,account_8fvkQS2hERUdtSF7DXrzpw,Corey Ball,2318,exact
|
||||
29442,toniyoung,RJ24VTRM7JA9,account_mXgG1ZhfDfrnkU6usym3kG,Toni Young,2312,exact
|
||||
29434,melanieweddle,XQ5L7PUM9RP6,account_piQoRw8BbqZpckbweTGdDu,Melanie Weddle,2304,exact
|
||||
29431,zackknuckey,VP5CCX8LTE47,account_uh8Yfj5mdjaQjofM19p9MU,Zack Knuckey,2301,exact
|
||||
29425,christinehamparyan,WEYX9R5P7J5L,account_aJuvQYQACJ5Ms48bAR4hWY,Christine Hamparyan,2295,exact
|
||||
29422,joespeciale,UH6ZCM9WLGRQ,account_2BwbPKVKpj7QnFFpdZVqn3,Joe Speciale,2292,exact
|
||||
29420,rogerbatt,KGDJZ7V66QQK,account_2gaAXfFo32nXEh7qA2yX8M,Roger Batt,2290,exact
|
||||
29419,kalebjames,KMQDGPD5XB6Z,account_67qbP4FpqwKmqSNjSmtCBv,Kaleb James,2289,exact
|
||||
29416,stevemolina,BLLHWPY9RCTC,account_c5VgNVVcBTRkHjbzFDEpHk,Steve Molina,2286,exact
|
||||
29414,mariatrejo,EYPWCQKKWYZH,account_ahaKfCrUTPA2mx7oM2i7Xu,Maria Trejo,2284,exact
|
||||
29410,kenhall,LX897BGJNMK5,account_gZPLTs7y5We8wW5MZyZjkX,Ken Hall,2280,exact
|
||||
29407,deewilliams,R8AGX3E8WAHN,account_kjSroty8KmGKCTEArNC9Pa,Dee Williams,2276,exact
|
||||
29406,johnvayo,DJJNUEEHGAW5,account_7hUzHAkpHagRdjPWYoRP9R,John Vayo,2275,exact
|
||||
29398,anthonythompson,WB4E4MPJVHTB,account_4CLddQNDWC76dtRwmYRdeZ,Anthony Thompson,2267,exact
|
||||
29608,stevecombest,STVN23552Wt,account_aM6WQ3aysaRPx4zpUh3zWD,Steve Combest,10015,exact
|
||||
29607,luisvelira,uygo875491!,account_3wT7DTZj4An5jaitLTTWTA,Luis Velira,10013,exact
|
||||
29609,keithtucker,14FYJSNUU48,account_7Wjw5Lru3JmVxq4s6cRqvn,Keith Tucker,10016,exact
|
||||
29610,angelatrevino,KJGU39565,account_4yPBWjMpwT4tVHJyVTDiYX,Angela Trevino,10014,exact
|
||||
29612,amymontelongo,ig76f7fuvu,account_o7rGD6dKJP27Sf9AUMK2e2,Amy Montelongo,10020,exact
|
||||
29613,michaelasmith,MS21353GHY,account_t23HG5uEXET828jSbivozo,Michaela Smith,10022,exact
|
||||
29615,janisstewart,JD834HCUW1C,account_fztV7NVRixwgnD6n392ZfX,Janis Stewart,10024,exact
|
||||
29616,irenegaribay,uky75dkc,account_ctACFtZH9mDX1E9tVgkpzy,Irene Garibay,10027,exact
|
||||
29383,leonardocoronel,TXPC494,account_bLMBbmXsvurdQQaSokRzTf,Leonardo Coronel,2248,exact
|
||||
29374,alejandrolimon,MM4BSQS7FRTD,account_gqFbPtxAGRTSizXXLFB9j3,Alejandro Limon,2239,exact
|
||||
29368,crystalharney,A7W26H834WLJ,account_bzPJ8YAjKNt5Bn7zhYf8zw,Crystal Harney,2233,exact
|
||||
29355,olgagutierrez,WERWRMUDBZ85,account_hswERjNGcJtQnPWCkMnEQs,Olga Gutierrez,2220,exact
|
||||
29353,greghummel,JV84HSVAK6XR,account_myUaLbfFVED7hqEBBY1Pe4,Greg Hummel,2218,exact
|
||||
29349,bettymitchell,8CHHCNBWQLRV,account_t4wwpPyK98WBZUqLnwXKNU,Betty Mitchell,2214,exact
|
||||
29341,wandadavis,JXQXXZ9MKFX6,account_iy49cEMsdawi18rTXarw73,Wanda Davis,2206,exact
|
||||
29338,scottanderson,RJ49A43SG3RA,account_sDPK3iLsxwrLzndTwh2uxb,Scott Anderson,2203,exact
|
||||
29335,jenniferboon,28ESU8ELVELP,account_3aCW8JeazPNe4UxjtGXzrp,Jennifer Boon,2200,exact
|
||||
29331,marialopez,P3FNSPT7MEYM,account_mjnZnogDMDws9ueMDxVzaP,Maria Lopez,2196,exact
|
||||
29329,cynthiasandlin,MCDTLMVFQXAV,account_sFzFdm2TTpyRaur4JfF3bv,Cynthia Sandlin,2194,exact
|
||||
29328,bethanybell,3UUC5X27PETS,account_wnvmzBJwB3r7pG6a6WNANx,Bethany Bell,2193,exact
|
||||
29323,garrettojeda,U5PRQYZE2MM3,account_chsr6oKpnEYuEKkMXn7CKF,Garrett Ojeda,2188,exact
|
||||
29325,rayschaak,XSNLP62EK6VZ,account_qhFf5wpTsv3FySr63biaRp,Ray Schaak,2190,exact
|
||||
29327,carlaswearingen,E6DQ4B2T9JZD,account_rzEn7BHU6Dmd6PkRwRpNXB,Carla Swearingen,2192,exact
|
||||
29320,lesliebewley,55KFSJMEDYLK,account_jeuzxdVtC5u4W8utfKf5vc,Leslie Bewley,2185,exact
|
||||
29317,delainawaite,EM7TWHUS4SYU,account_kvePVE9fNZCokbkkvpBvLK,Delaina Waite,2182,exact
|
||||
29307,esparanzagarza,VLL9ZNPRSTG5,account_dXq5FqPpKhAwE96NT5D9Jk,Esparanza Garza,2172,exact
|
||||
29273,glendabeauchamp,RKA3J8WSPYJP,account_fJVr5CSPdsgWtLNRWkidro,Glenda Beauchamp,2133,exact
|
||||
29256,glindarichter,VXMLMDAFLNJ3,account_2ngDjpr4VqDCPsv2SNMHvS,Glinda Richter,2117,exact
|
||||
29251,nhumorrison,EC32VDFKB9CB,account_hZpk1bujwvFdyctrbfJtjS,Nhu Morrison,2111,exact
|
||||
29245,brittanyworley,NBKYERRBSBH4,account_r39MCaQ811VXnw6QbhSG4b,Brittany Worley,2106,exact
|
||||
29243,dustynfisher,XASFU3DBPZ5M,account_sAYv3pn9D1KCwWr1TzGyeu,Dustyn Fisher,2104,exact
|
||||
29237,stephenbeegle,RU5GZVTVACRC,account_7RPLicRiJMb3Y1x3C4tEQJ,Stephen Beegle,2098,exact
|
||||
29229,roseanndellavalle,5GAF6JHUWWYP,account_wTXj1c59SU9iRzeRmgv2dT,Roseann Dellavalle,2090,exact
|
||||
29231,duanewright,VXK4FBLVFE7F,account_3Hwm7znAWKLPMhmY2avtnG,Duane Wright,2092,exact
|
||||
29222,pablohernandez,P3YB6A4JGEDF,account_vkMiPuMKu6XmQt1G9CP1op,Pablo Hernandez,2083,exact
|
||||
29217,pavelavanesov,KP8ZSGC2DG2U,account_kNWT9ewUppfxMtxpcgScKZ,Pavel Avanesov,2078,exact
|
||||
29204,sandrahoughton,5XR4QMPBXVWY,account_sDBLs44VLbWy9ZRhuDAkpL,Sandra Houghton,2065,exact
|
||||
29203,adamstaeben,GP7RANJ8UCYP,account_u39DmoPasPkSoYJ3bTG8kz,Adam Staeben,2064,exact
|
||||
29190,russmott,J8ZN888UQSLR,account_7QghTwmH6MwtZdTrvur8uB,Russ Mott,2051,exact
|
||||
29189,karenstewart,JSKTFAJ2JYDX,account_wSUPq2ZjUF1Va7S3vap91M,Karen Stewart,2050,exact
|
||||
29185,heatherwomack,89W7S5Q7UAHP,account_kSE9uAW6WPbt4msXe4mzHs,HEATHER WOMACK,2046,exact
|
||||
29183,wyndijames,CPSDNRQU95HJ,account_hJwbN2EUqGCtNj45JCyQda,Wyndi James,2044,exact
|
||||
29182,angelicacuayahuitl,VK8PZW3LK5F3,account_sooioQ729DC21LJa1zKMAN,Angelica Cuayahuitl,2043,exact
|
||||
29181,chasewilliams,W6AMPQEPY3BC,account_iQqfYFDTb4UxtHcgrGt8EP,Chase Williams,2042,exact
|
||||
29176,kevinarana,JAJYSEG75UZS,account_oR5nKGJTvRLhkCyUGG1B1L,Kevin Arana,2037,exact
|
||||
29166,chrisclayton,BFJ462PLHJFV,account_aamYj92hC8r7nxvbAfiHCE,Chris Clayton,2027,exact
|
||||
29162,billyhorton,MPTX573ZUYYG,account_4DuPXfEqx5pRPftTGKkbhS,Billy Horton,2023,exact
|
||||
29151,chisediquezada,RJBYQ2NUB829,account_1KjfxaKx8MvMEwb7uU3eSC,Chisedi Quezada,2011,exact
|
||||
29147,angelmerlo,EWWAPXN9Z2YS,account_deGyZc4zP5TBJGSibkGU3a,Angel Merlo,2007,exact
|
||||
29113,kerryblack,9D5S9ZD2FCBV,account_qncL4zimMnsq5ViZrpNXr1,Kerry Black,1974,exact
|
||||
29110,cliffordjennings,5GC7M65H9VGT,account_rknD3GcgUkTd8XB7rZZjND,Clifford Jennings,1971,exact
|
||||
29098,carlakimberling,SS4KRJYKTV7B,account_2hJ8frAhU5LDVpaoSH27Tx,Carla Kimberling,1959,exact
|
||||
29088,richardconklin,WEUNG5H3K8BB,account_7aEgkmhMKwDVqsus5Ln8Bd,RICHARD CONKLIN,1949,exact
|
||||
29089,leandrabeshea,7V8BZU4G83VF,account_doS7HkZWacVd5r8nWxqDFZ,Leandra Beshea,1950,exact
|
||||
29067,robertfinch,D7FMTT455GBB,account_jJoU6UPYd2ckqbUhynBx7B,Robert Finch,1928,exact
|
||||
29058,ericcoffman,MMEBXQYLZWNU,account_4mZAzz4GiGtMU8CJBWs1cQ,Eric Coffman,1919,exact
|
||||
29050,nathanaelfinch,JVNC68FV7N6B,account_t87r46C6jaw8rjJYurmHrY,Nathanael Finch,1911,exact
|
||||
29047,gabrielasereno,KCH82WCRA2YR,account_99RoiQcJpubSAqajPZjxFf,Gabriela Sereno,1908,exact
|
||||
29045,georginacovarrubias,8QT57NUV8C7R,account_gERfDmYXtJj5PLCY9ELLS7,Georgina Covarrubias,1906,exact
|
||||
29035,thomascline,E523BKVU5MJP,account_g8yP63NFmbioePagUH1kQS,Thomas Cline,1894,exact
|
||||
29034,susanlewis,R7TZFZEGLNRW,account_mqMu7hR16hGpAesQ3ba83B,Susan Lewis,1893,exact
|
||||
29025,tammywelborn,RMC482WNBS7,account_rjvhtkZxuk442ghJaKsdtG,Tammy Welborn,1878,exact
|
||||
29023,haleymuela,BS7X3DTKW8TH,account_hmnByz3wfiafSujapZBbi3,HALEY MUELA,1884,exact
|
||||
29018,christelles,WL2TKLFG8G2H,account_uGdvd35CHuBkiBamMnB8Bj,Chris Telles,1879,exact
|
||||
29017,mauricioantonio,6QJW7RAPDBWB,account_tX9wv8qaDb4bCFBxKPsMDe,Mauricio Antonio,1877,exact
|
||||
29013,vincentlimon,YDDXKFABUZY7,account_eZ6nJGAsmsPwR8sYvtXBRw,Vincent Limon,1873,exact
|
||||
29634,jeffreyharder,YUV565D67RT,account_gWD9gTNmR8RbzQkJmjpRYy,Jeffrey Harder,10073,exact
|
||||
29635,pablomartinez,2766581BER,account_g2THEPVu4zgnGsTeFh6MpF,Pablo Martinez,10074,exact
|
||||
29636,krystalmendez,6FTCKU6S56,account_hiH7WbsYQm1HRkpGA3jJ2v,Krystal Mendez,10080,exact
|
||||
29637,davidvandagriff,UTRC53865F9,account_kAa1VyPLqz5fecRMXpV7d4,David Vandagriff,10082,exact
|
||||
29638,carolynwalker,trjxtyx75!,account_wsZpXzz2mhYMxMLmiVGNvF,Carolyn Walker,10084,exact
|
||||
28979,claygilbert,3E6XFDHXCAG7,account_eVxdo9RAAoBbisk1EYCKnc,CLAY GILBERT,1839,exact
|
||||
28978,jmichaelculverhouse,2147099521,account_q4nxMiXUoEj2DkH3JUspLP,J'michael Culverhouse,1838,exact
|
||||
28971,diegosereno,2CE9F5YSPQHX,account_vvPvzpGka7xmJQnqE3gMxq,Diego Sereno,1830,exact
|
||||
28970,ashleysmith,F8D3FVCZB7PD,account_5nSRJ7EkJpz5dpB2QGRYfz,Ashley Smith,1829,exact
|
||||
28954,dougstowe,5D35LFD6GEAZ,account_3hQJhhHf48sszYWBaMTjpR,Doug Stowe,1807,exact
|
||||
28936,timbronschidle,3ZVLCWSAE3EW1,account_o6gDBbdWzQYeUbAQL2Zp1s,Tim Bronschidle,1788,exact
|
||||
28928,cynthiajones,KC7ESYHEZGNR,account_hJ5wonckmH2jkaykKH2g4Q,Cynthia Jones,1778,exact
|
||||
28867,bobbymack,UDUBTCXXF8VV,account_nNUBZtEptfAD6TpDteqjfM,Bobby Mack,1712,exact
|
||||
28848,americatrejo,3B63TLTT9WE4,account_gjzpfGyVuYMaQwdYA2Gufy,America Trejo,1693,exact
|
||||
28832,tjbanschbach,8WTWTXACGG5N,account_hU5voij99AKqckcGpok7Jx,T.J. Banschbach,1676,exact
|
||||
28811,luiscabrera,RWUQ94XT9A9Z,account_mrPPtWesWBzmcD4Lfvp2hA,luis Cabrera,1650,exact
|
||||
28810,rosahernandez,JSGUXKWEMSVN,account_qYeNtZSW1nYgukr9kYy5qn,Rosa Hernandez,1649,exact
|
||||
28807,carlosgomez,J22RS7F3LGG2,account_jNj9rpkTwq7wF3vJbMuAkF,Carlos Gomez,1645,exact
|
||||
28763,jeridrutledge,GJ3CZTRJJW2M,account_v6odXP1nVxoVvTMUrUn3SS,Jerid Rutledge,1601,exact
|
||||
28748,timthomas,NY223RQJD7PN,account_m5ZTZYHZbzpVPeNfRhroxn,Tim Thomas,1585,exact
|
||||
28715,carolbates,J3UBUCMYDX64,account_97wbzzkGPxCPMyfUs5uTTf,Carol Bates,1543,exact
|
||||
28710,shirleyelmore,D8Y64N9L4R9W,account_gfPawVk3gSuvufuC4zVjx9,Shirley Elmore,1538,exact
|
||||
28698,swedlund,swedlund494,account_u9nP4wDufL6eQGx3Jnoyn6,Brian Swedlund,357,exact
|
||||
28695,wendysanders,RYG9L43NWDZV,account_4KPsmHxqdcnsRNXuWB8s2Y,Wendy Sanders,1524,exact
|
||||
28693,robbymccollom,RMC482WNBS7,account_xfht7KCxBpasoRqtkTojjj,Robby McCollom,297,exact
|
||||
28664,heatherbrister2,KK37V8W9ZD9Z,account_m1hacYUopGGJrn2UyJvzBu,Heather Brister 2,1495,exact
|
||||
28663,ryanlloyd,HWEMKNWX55RF,account_pFHZ8RMuvdETPpHr4vyDWi,Ryan Lloyd,1494,exact
|
||||
28661,amyrodriguez,WX3QRT2U6L4X,account_w1ywM8kUBcURQHGjHQqirn,Amy Rodriguez,1492,exact
|
||||
28660,thecountrycutter,YXpScFIneePm,account_1uu6CnSCUuCfBabMwfikLz,The Country Cutter,396,exact
|
||||
28659,bradwilson,ZFAXA9AK63AH,account_ujyp8hfbksvc8EZALQ5gTL,Brad Wilson,1491,exact
|
||||
28654,edrater,FRY4823N,account_fNtXkw98GQKVvcjcfbeb9F,Ed Rater,126,exact
|
||||
28637,vikyacosta,Z4SMV49SAH72,account_mma7TzxJUZKUzXYr6YDUmt,Viky Acosta,1470,exact
|
||||
28633,terrimack,B9HNTSN7ASQ4,account_wU2qgfTxqjaLSfhwWx4Cxm,Terri Mack,1467,exact
|
||||
28617,luisarellano,GVNWBQMM3S7U,account_t9DUQUCtBAWojjSYtZQusE,Luis Arellano,1450,exact
|
||||
28609,dorisavalos,DLKMJS88AF2W,account_pMdxeChdNqnVRQs1rSAKBE,Doris Avalos,1441,exact
|
||||
28597,jackierollier,TSFNN8DVDSPR,account_w5t1gDksfLnZqU35RFxZES,Jackie Rollier,1429,exact
|
||||
28588,charlesmccreary,88J6XS6TXRMA,account_dQ3cvFTw98ByhcBzDGMsNQ,Charles McCreary,1418,exact
|
||||
28548,jamessmith,LRVU6RVG5SP8,account_ayvJr4cDCtK3zNPcoVo5vy,James Smith,1373,exact
|
||||
28546,davidwhitefoot,PYHTZMHJU8R8-,account_sWngcEfTk4Ed83ARWYtZga,David Whitefoot,1371,exact
|
||||
28536,patriciavasquez,P88256487V,account_6wngyAj64jCwvn3W8T3sdT,Patricia Vasquez,1128,exact
|
||||
28535,adrianmcdaniel,U4TGDH2PSAB4,account_aScSfG25Wwo7cD4xbNhja1,ADRIAN MCDANIEL,1362,exact
|
||||
28526,justinvoga,URHVCX7SFSFU,account_cwmXrKm93bSteHQfm3SJtd,Justin Voga,1351,exact
|
||||
28518,jenniferlittle,8EAUUDQPXSQX,account_oSA465twDMxZedY5zbPLT1,Jennifer Little,1343,exact
|
||||
28510,bradslate,AF4KVQ2P44M7,account_nhYxp4RV7gpLxWnLL9oWs6,Brad & Sherry Slate,1334,exact
|
||||
28494,irisdelira,L6XGQA583DG6,account_mVgspPEmufZG8KD83Cnyjh,Iris Delira,1316,exact
|
||||
28491,richardbarragan,WJBS86MMJBFH,account_hJ3iUD77LRADfhaxwwsqLj,richard barragan,1314,exact
|
||||
28476,jensenhall,F8XM9U8SC6LL,account_m3356qm8wGGJDqNZCgXRev,Jensen Hall,979,exact
|
||||
28466,paulcomella,YTZDMBZCMPX4,account_rRKbPsCejKqMnAb29xPPFx,Paul Comella,967,exact
|
||||
28449,amberkrings,5NWBR3JLV6N8,account_eB2k88UWVdAFKYgcg7iK4h,amber krings,1273,exact
|
||||
28438,mauriciosoto,DJ7YP7W7AA8M,account_uyp7QDJmZyCeq9BTGnvoZ3,Mauricio Soto,891,exact
|
||||
28435,jimcrank,PLA7XNX2F4Y3,account_p9AaVzWfCwR74RVK3k6kPa,Jim Crank,1257,exact
|
||||
28425,summerbeazley,D4S4YRB8Y3KA,account_9AkWnUdPzs2AE9vfqmbz6i,Summer Beazley,1244,exact
|
||||
28426,davidarmstrong,MPEZGG53KQSZ,account_p1wD82RWMCTi1hRoLHdjHL,David Armstrong,1245,exact
|
||||
28395,stevenspurgers,YS5Q785J2HGZ,account_nxruUEiwq3NpZTexeEo8jd,Steven Spurgers,1211,exact
|
||||
28388,connercoleman,6108RANDOMREDDOG,account_6VLrBr4sZCAJwMzzcEkhSE,Conner Coleman,1202,exact
|
||||
28367,judithfierro,FUZ33LB6SFFC,account_aFYkyi9DGrJBRgQ4jSud96,Judith Fierro,1177,exact
|
||||
28359,tonyasipes,N5VEZR8Q5M86,account_rKLQuRuTgybF3YMnNt7VY9,Tonya Sipes,1169,exact
|
||||
28347,kathysmith,SJ53PSYCZLPR,account_3zbkHwfVAegXCPUhc4XmYV,Kathy Smith,1156,exact
|
||||
28344,cherieeshelman,BRUV99PN6Y7L,account_nwbZPHiXLbR9o6LZppPSoY,Cherie Eshelman,1153,exact
|
||||
28289,ronberger,Ronb499H7ALW,account_q8QjfTJ9rtgoow3eHLpVYQ,Ron Berger,301,exact
|
||||
28267,sandracrouch,V4N3764R5J,account_tCddLw595sDcQEYCrRCmFq,Sandra Crouch,311,exact
|
||||
28263,abbieandrews,YQSJ499H7ALW,account_vHWu6NZDh4Ajh6YqWEXPb4,Abbie Andrews,1081,exact
|
||||
28253,perlachavez,ZWR9PXVFFYBS,account_tTLx1Zn6YTykzm8quV6ykg,Perla Chavez,1068,exact
|
||||
28246,susanking,N2KUYLPDNXJP,account_xqwwg1ZAd6SKt4LyrcAebY,Susan King,1058,exact
|
||||
28241,terrybachran,NG9VMH25LCTC,account_s6ZC2GALaCFUamcQafLyy7,Terry Bachran,1053,exact
|
||||
28240,lanaygaunce,MJCNZAJHK9H3,account_pUesJC8A4ENdQ5XZTFGdZt,Lanay Gaunce,1052,exact
|
||||
28190,heatherbrister,6XPLC545G6HW,account_wkn6qdAVF72b7TxwZxvW6D,Heather Brister,997,exact
|
||||
28184,jenniferdunaway,343V5CT2R7HZ,account_bTsNpp5j2YHU9dKipBm3iP,Jennifer Dunaway,990,exact
|
||||
28159,elviraquezada,HXAS29VRX33V,account_q5J8BYNnSG5TtFnikCTEmm,Elvira Quezada,960,exact
|
||||
28154,jordainpatton,J8P4TPF7QS2A,account_p5VqKAXXC8t3tAFSzzr8cC,Jordain Patton,955,exact
|
||||
28140,mattkosarek,RJ4BQUZJY,account_7eCHrmvA6X16gn1zr5wCo9,Matt Kosarek,932,exact
|
||||
28117,shannonclark,F5XESMCJ,account_8YqGj24SS5fxoZhPUYBED9,Shannon Clark,908,exact
|
||||
28098,kevincostanzo,244VGMVMH66D,account_9DuddEuiaH59KtVGReTwJs,Kevin Costanzo,881,exact
|
||||
28093,kenpatrick,V7U3XBAPTSV3,account_omX4bSM3rXDShahsdc4aHd,Ken Patrick,875,exact
|
||||
28083,briangallimore,39V285NX,account_k8GTscTwPuAvgtyCbT6vyG,Brian Gallimore,55,exact
|
||||
28072,amberprater,RP42B7AYDLAP,account_fXqciwzW348S1eYSKbbi8B,Amber Prater,855,exact
|
||||
28068,marilynfowler,MarilynVG72P8H,account_v9vCsfc4uMAk7LgXyRR9EC,Marilyn Fowler,851,exact
|
||||
28065,douglaswilson,HP97HG9XPYC3,account_bmXh2S5K97hPyUkkBRj1ub,Douglas Wilson,848,exact
|
||||
28034,terrygortney,GQUGR3VJUXBR,account_jPuzvdHGq1BXiDALjrVaR7,Terry Gortney,815,exact
|
||||
28031,gizellebutler,HMZTX66RTPVX,account_fipAsvnLVUkrSmuJ9GYdEb,Gizelle Butler,811,exact
|
||||
28029,bradgurney,7A6LRZWT82DX,account_aZMRveyhHvJTHTQCT7yYdf,Brad Gurney,809,exact
|
||||
28024,darrylchavis,TDGUUNXGMYRC,account_oP5ATcm8WwBDBv8t8mh4vU,Darryl Chavis,803,exact
|
||||
28025,kathymazzola,5MVS8VUF9QL2,account_g5RpJWMv32tFk6c4yy5F5c,Kathy Mazzola,804,exact
|
||||
27994,austinwatkins,S7M4UD8QUTDP,account_htyg2uThjYmLbHsX5a3RCj,Austin Watkins,769,exact
|
||||
27988,oscarrodriguez,TGPCF3Y2ABXS,account_fNLTDkPjpbzZ7Eta2ofer4,Oscar Rodriguez,762,exact
|
||||
27986,erinthompson,69TQZ797,account_eGe4Qkw13xjjwabHBu51F3,Erin Thompson,394,exact
|
||||
27983,brianhardesty,8D4P34N8,account_7zjMVqCfCV4jZT68myj6p1,Brian Hardesty,20,exact
|
||||
27976,cathyday,FAXMKENV8FCT,account_aZmcKqobMWGKhxagDdLCFA,Cathy Day,755,exact
|
||||
27956,fredheckel,HUVZSE8RGD65,account_mx1SSXHEiptCZaz2Gx6MTm,FRED HECKEL,735,exact
|
||||
27949,charlesboone,Ccbn78wdfksB,account_iNnHAwxaWRUXte6w7ijGV3,Charles Boone,62,exact
|
||||
27948,rachelguzzardi,R87wgerf8bsG,account_tEZyHoiA8DvmisscRkYy7U,Rachel Guzzardi,287,exact
|
||||
27936,juanalonzo,745GF0JK5!W,account_itAy96jDYGcvWjcHsy6XcR,Juan Alonzo,198,exact
|
||||
27930,kristinamurphy,oPXFrylqKf,account_qx5oYHwkMNxoKEXME6zu6w,Kristina Murphy,725,exact
|
||||
27926,johnnygoble,J829fhf7G,account_1m7oDB9vYUYJQffFHvxQaz,Johnny Goble,416,exact
|
||||
27923,keithbarber,K73bvd54tB,account_bKdyNcZqZ1h8qaQAcJzTRK,Keith Barber,208,exact
|
||||
27917,doreengrubb,DOR32SVT1234,account_5n5qjvMULWVYcGGmF7uiER,Doreen Grubb,122,exact
|
||||
27916,steveraia,DRR648DFTMSE4,account_g7EjAfDhcTH9oxWZGJ4CTH,Steve Raia,291,exact
|
||||
27896,twcowley,TW486TW,account_h2bYtWBz1nbRRVBiYvi8wQ,T W Cowley,710,exact
|
||||
27888,joepatton,L7luYzSKSu,account_hWsePAjG5pq8FnnDQm75GD,Joe Patton,701,exact
|
||||
27873,timfisher,Thd73gdf5eF,account_hMQqEcyWpzLTEtUnCJmKsi,Tim Fisher,345,exact
|
||||
27847,kileigheven,K9872gdf8E,account_4aPqi935STSGBSMxsLNwSm,Kileigh Even,215,exact
|
||||
27833,deannecook,Dc872cobnC,account_hqsfU7P5wK2uDjpfVo8zxb,Deanne Cook,110,exact
|
||||
27830,kacyharrison,7Ozr7el6K1,account_t9Bb9uXEB9NjGoTDvCThi4,Kacy Harrison,643,exact
|
||||
27822,milliganwater,8NjGMNsTXd,account_7FafmmaEuKaNeaHmFFLSaf,Milligan Water,636,exact
|
||||
27813,michaelnewby,TM5M3HU877,account_1moqtbSRAJxiVR2pTtH3f9,Michael Newby,623,exact
|
||||
27808,ladonnaclark,YQReVH9men,account_vPgQBpVJ4y2gkpRgWTksvi,Ladonna Clark,612,exact
|
||||
27800,jamesmooney,QNUqD2tSzq,account_5C4WjLaQS5tGDxZm4NCZds,James Mooney,603,exact
|
||||
27783,tamythomas,TT4699520858tt,account_4gF4CqD6W7iS3UesE6js3g,Tamy Thomas,587,exact
|
||||
27780,josephcruz,Z06oxJXrNd,account_nYfEqA9HUY6R2xi1PvCQVs,Joseph Cruz,583,exact
|
||||
27761,franceskirby,FK8179391152fk,account_v2eMTZjQzV5Q3B2vLxGCpa,Frances Kirby,568,exact
|
||||
27759,chadwhitsell,79374B75phGy,account_swiMEEPxqsGukTQMUEP7DR,Chad Whitsell,61,exact
|
||||
27754,ruthfengler,8q8MX6NQP3b6,account_2ycJgX1XpXSqDiDgNisZbA,Ruth Fengler,304,exact
|
||||
27751,bobbyfisher,salvagejuggle,account_iuZZQ7KJWWSihZh9mzi2B8,Bobby Fisher,391,exact
|
||||
27748,eddieyarbrough,89298ChZWzMy,account_6KuhoNq2CptmBHyHVS33cS,Eddie Yarbrough,125,exact
|
||||
27744,chrissyeagle,9vkX97426Sgt,account_3uu7k4euycmKnZii9DQAj2,Chrissy Eagle,74,exact
|
||||
27739,victoriaobier,M57B288P9,account_cPSKw37hjbGmmpHzzHUum1,Victoria Obier,371,exact
|
||||
27736,bernardheer,BH33682019BER,account_fcUL4WRuUX7LrvPhjfQZQt,Bernard Heer,46,exact
|
||||
27734,garycable,M2w6z5Y73,account_6JkDjyFzfp7pPcvn6tsd9f,Gary W Cable,144,exact
|
||||
27735,coyungemach,MhS569N84e7a,account_f5ygK53FvcVakZs4YwNVo5,Coy Ungemach,84,exact
|
||||
27733,michaelmccauley,CPORADIO98,account_ecewjvtr229nzEjFgSEhf5,Michael McCauley,259,exact
|
||||
27731,lessruble,9U35SXxM2H8y,account_6M1cjjzHDyrtJWimoD6Tgp,Less Ruble,226,exact
|
||||
27730,marknunnelee,833j2Ymm4yfV,account_mBYcBCnbFTgVxsDNCUrq9z,Mark Nunnelee,243,exact
|
||||
27729,elizabethchristian,Webg22nj,account_3Xpb7LLq4bEFZxohgYvjUS,Elizabeth Christian,128,exact
|
||||
27724,mikebell,BHF538HSEBDLY4,account_4vuDbTF964RUD2YKA5hmhQ,Mike Bell,556,exact
|
||||
27713,krystabates,KB2145445824kb,account_crxqAidS35hAeKLFDHKmiy,Krysta Bates,218,exact
|
||||
27708,chrisfrancis,DR45QC74M,account_pcYVJfTDAUK9ALviS7XBjW,Chris Francis,388,exact
|
||||
27701,markfisher,32fd8P&rw8s7,account_hxsSqNHZMtFbXDA8DtvRso,Mark Fisher,242,exact
|
||||
27696,kirkvanmeter,J2sR9g^83M33,account_bH9zyBQuBcgkiU9EZPYxa5,Kirk Vanmeter,216,exact
|
||||
27694,dananance,23SP$e!ug232,account_s9ZW1FpS3wkDoh31CjU1Zw,Dana Nance,89,exact
|
||||
27690,keithcrank,2zt3T5w72T3A,account_iSuzVkNmem52NdXXh1Savu,Keith Crank,209,exact
|
||||
27687,scottarmstrong,2SV58M55,account_dCvreFY2K3nJW8ZkCPaeyR,Scott Armstrong,315,exact
|
||||
27683,floydday,Tfdd3254tfD,account_rFM2cz415W3Rqn1McU5gpW,Floyd Day,141,exact
|
||||
27680,mariacortes,MC2145858276mc,account_t4Qnzxsq3c2WryFDXTSWba,Maria Cortes,435,exact
|
||||
27668,christianlummus,K6dbr631ddL,account_fWd5egSy6XovRRzTgi5xZk,Christian Lummus,205,exact
|
||||
27666,marklindsey,ML9727346434ml,account_ayztehQeAayBTQkizozi2B,Mark Lindsey,531,exact
|
||||
27658,joeywhitfield,BV758qXne446,account_8bxr54hmvSEFRyDLfvCgie,Joey Whitfield,187,exact
|
||||
27654,taekim,SAN11837TCK,account_wbsKtfE9W1SyPkqk9hFBRp,Tae Kim,408,exact
|
||||
27652,teresarobinson,T645trdf87fR,account_2SA7BzkR6cqsS2jSQ14nRh,Teresa Robinson,376,exact
|
||||
27651,nathanmctee,N32462uu8rM,account_2CZKhrkB2TxZDQTWxuJxVz,Nathan McTee,273,exact
|
||||
27646,rebekahmoore,R756346tfg4M,account_k8gD8YGUQzwWCE7JT9EfYc,Rebekah Moore,386,exact
|
||||
27643,monicatrevino,MT2145877143mt,account_d3CqUjkDwdiB1pwR6t66XL,Monica Trevino,524,exact
|
||||
27640,rachelfuller,R8364hbst,account_t7qMv9PTBxtj1rmr4WmEqV,Rachel Fuller,286,exact
|
||||
27638,shannonbrown,S9725298223b,account_nZ8roCqzpsY5Wv86p8i6Sq,Shannon Brown,318,exact
|
||||
27637,allentaylor,A6346gge8T1,account_44F55EHwRrLm33EvyuCPgG,Allen Taylor,26,exact
|
||||
27632,kristenaustin,KA8017916972ka,account_qunWwkhDGN8jxGDMfB9FzA,Kristen Austin,522,exact
|
||||
27630,colinhopper,TYVU65445IUB,account_jaGX2dnVZVs463ok5kANR5,Colin Hopper,245,exact
|
||||
27619,srireddy,ycHAvetmF0,account_jS3WVFZmrQu5EoM7UJ4L1N,Sri Reddy,514,exact
|
||||
27615,almaacosta,ENKC5DGV,account_rv1k2oTH5Dn7sDTJiTxADa,Alma Acosta,28,exact
|
||||
27614,chrispassonno,C8766thf96P,account_8UMvyYLatGW2qwSqH62KbM,Chris Passonno,73,exact
|
||||
27613,seanbaxter,SB4696679337sb,account_vFwXqaiaquwHXzgMkdg1mc,Sean Baxter,512,exact
|
||||
27612,collinhartman,B886tg98jt9L,account_kvBUopRRFzz8B5PgbdjLGG,Collin Hartman,402,exact
|
||||
27610,michaelhughes,1RKk32MyTK,account_6QT3zjSA88VLdbBJtAt44j,Michael Hughes,510,exact
|
||||
27608,michaeltalbot,Mjj1276rt99T,account_4bK2RJU3FRwyH4SPmnik1q,Michael Talbot,262,exact
|
||||
27606,anagonzalez,WNAHDMwWoE,account_3jfw5hMXURMmVuGyafdSPj,Ana Gonzalez,507,exact
|
||||
27604,leonardlewis,L1877ef32L,account_3TVj7ZpGiTYYt28q8dh9VR,Leonard Lewis,224,exact
|
||||
27598,jerryjohnson,J177895aa98J,account_fa8emiMvGC9ZkdA6uuwMpF,JERRY L JOHNSON,177,exact
|
||||
27594,pamtoler,NfxcgYQUbj,account_mnxwgFcvbjvDjnBBdGQzek,Pam Toler,501,exact
|
||||
27589,jodymccluskey,JM4696883349jm,account_35QGS4ZHr9tSpCVKNHE1ZT,Jody McCluskey,497,exact
|
||||
27577,chrisvannatta,!4694502484!,account_dyfr7aKWGD5zJ1pdeEyyna,Chris Vannatta,426,exact
|
||||
27575,mariomerlo,!2149579585!,account_3yQbySMiwrU5kFJRA8itm6,Mario Merlo,239,exact
|
||||
27572,williamarmstrong,!2145510334!,account_5izwKtCxbvkCupVQJ1KBBE,William Armstrong,362,exact
|
||||
27571,trecedaschmid,!4692075942!,account_iR4oM82C6m8zkrFDLkSbYZ,Treceda Schmid,355,exact
|
||||
27570,ronlewis,JDkf1AL942,account_5Y7chdsykaLwBg3s2rqvMD,Ron Lewis,302,exact
|
||||
27567,sherryerichardson,DR6528BCD3S2,account_oadyDfiynqanaMffoSVM2W,Sherrye Richardson,321,exact
|
||||
27566,joannarodriguez,394X3YR9,account_gCVrkxTWdSWaYUNtyk1rqr,Joanna Rodriguez,185,exact
|
||||
27561,dannycampbell,!9726589541!,account_4ww28eUsFRv8Yh5RkWe9cz,Danny Campbell,92,exact
|
||||
27560,howardcomstock,!3365494230!,account_kZMVM4zfKdgEAyCCvVREU8,Howard Comstock,156,exact
|
||||
27555,terrymiesen,!4697420828!,account_bXRRk1Yz4nKkCPsdzDJyYa,Terry Miesen,339,exact
|
||||
27550,michaelray,primitivedefinitionstoredinner,account_8Rh7edwTjNBYw9FJSq4WRT,Michael Ray,379,exact
|
||||
27545,terrybates,!2145786644!,account_d6m5HYMAczoeH2ovA6vqxj,Terry Bates,490,exact
|
||||
27538,gregmcintire,v9368$E9mx9m,account_fyH3ZiVVLx9h56vNYVndbK,Greg McIntire,380,exact
|
||||
27543,beverlyerwin,MOOLAH,account_9kYh3vsMa7mG8JrGaQtF2V,Beverly Erwin,48,exact
|
||||
27518,helenlumpkin,Heehhejd0N,account_ts53K9Gc61HkXi7uqcaiN6,Helen Lumpkin,477,exact
|
||||
27508,stevechristiaens,zY272m258*vJ,account_3HSd4Thc3iXfcidraN6ZSV,Steve Christiaens,329,exact
|
||||
27505,judydevine,OD4697669725od,account_e8ZUaWmpXqA5NTVfBHaYfq,Judy Devine,277,exact
|
||||
27500,rhondabolton,RB2145786030rb,account_x8xohdUBJBWyd87jTCtP3r,Rhonda Bolton,295,exact
|
||||
27492,rickbeckham,tVj7ZI5QA0,account_f861cgYw7zxSiyUh3ngUYk,Rick Beckham,464,exact
|
||||
27490,vancepeltonen,V66rdf43aaP,account_9arNHyqn6bwuUyPm4uWfrx,Vance Peltonen,356,exact
|
||||
27486,jacobwilliams,jnlka9994jkfldsa,account_bFr4VtSNkJpdZv3K67mP5y,Jacob Williams,159,exact
|
||||
27478,classicshear,KARENALDERSON,account_tui6mE1CTprghAF31hKWLp,Classic Shear,400,exact
|
||||
27477,davekiowski,FNW63KXSAPT7,account_xr9LPLBvR6SHF2xmNdrNfN,Dave Kiowski,100,exact
|
||||
27458,paulsammataro,P2n74V7P8g4S,account_cwYTP5p9ubFdXioqnmuDsy,Paul Sammataro,283,exact
|
||||
27460,janetkern,j42252^Bhf44,account_skzmJw1vJfndNPQNWsJjRL,Janet Kern,449,exact
|
||||
27457,carlossalaises,28E358y$JFB9,account_5mD5W5PczTzo9H7it3qxLX,Carlos Salaises,448,exact
|
||||
27453,obedsandoval,*H78z9xy84C&,account_k6qzzjxrJtH4UT7BerwBzk,Obed Sandoval,275,exact
|
||||
27455,dianewiley,Diane03t4&adTL,account_n9yXaEBkPmAm5SdrbTwsTw,Diane Wiley,442,exact
|
||||
27444,tammylove,f65NS4Ct6$29,account_5WZN3aLBoWBUHeEjHYySgw,Tammy Love,335,exact
|
||||
27438,floydallen,V3864VB2,account_9oLnGJZwNxJTrJRrQgCX59,Floyd Allen,140,exact
|
||||
27432,hortenciaalvarez,WHTABORG3593JKS,account_oNBXVRFamuurD1rz4bugiE,Hortencia Alvarez,155,exact
|
||||
27424,timbagert,CF18n42cY7,account_2U67Q5pWZCgbWGX1tLXbXD,Tim Bagert,343,exact
|
||||
27425,davidbaker,DB764g1d87rtB,account_okpeaMgrsz9nNs1cSMjQv3,David Baker,102,exact
|
||||
27421,janicealexander,AG57TSH89L9,account_pdQ864pRJ5AbJP4YHtv1S5,Janice Alexander,165,exact
|
||||
27423,timgilbert,73xi0r600Sz%,account_ezDVFeaw9XwLiVvM9iEDwJ,Tim Gilbert,346,exact
|
||||
27413,jesusrios,8Di6QMs7%7m1,account_5RA5zrZJXyuBEj4CmuodCh,Jesus Rios,181,exact
|
||||
27409,veronabaptist,DAY753LIGHT253,account_j9cuBn7ojxwRH3BfRWmDhN,Verona Baptist,382,exact
|
||||
27406,whiteywhite,45z6r*H4418n,account_32CUFBTH16juiHGzrKPd7m,Whitey White,303,exact
|
||||
27402,louislafon,RFTRE4825CVKL,account_9ayF1oF9iawPMpCdQSiSqX,Louis Lafon,445,exact
|
||||
27397,ausencioluna,ABN765MNL,account_7Gj6TBTXHmpu49iZGZBYT4,Ausencio Luna,427,exact
|
||||
27374,davidvillanueva,DV5489CRPMWBQ,account_d5hcuzxZBgMErVfhrXzQAJ,David Villanueva,109,exact
|
||||
29621,coryrees,yt5c6ujhvu,account_uRC7LnETNNZdRmSEQeQbwX,cory rees,10049,exact
|
||||
29622,brianamartinez,ktydr6428,account_gazJNXCsEwG1UJBmYyQ6xB,Briana Martinez,10051,exact
|
||||
29623,khushbooagarwal,UUTFVUCTC446,account_5xtd1ApTppgpHnRpvmQHmV,Khushboo Agarwal,10052,exact
|
||||
29624,elisasanders,OYTCu3276,account_hZD7ECmwCWd5vG73hEYDUN,Elisa Sanders,10054,exact
|
||||
29625,josemedrano,UYVITRUR24,account_3froYZwHV4X7v9wW6TVu8N,Jose Medrano,10055,exact
|
||||
29627,nicholasterry,VUTYVL746,account_wSzw7Xd3wb871Ug9aaqUcH,Nicholas Terry,10059,exact
|
||||
29628,leslieperalta,RYC66747,account_dQfUEUmdqUu6rGALsoowVQ,Leslie Peralta,10061,exact
|
||||
29629,khushbooagarwal2,iytf65gkj,account_j2iH6cW5tFhsSKxjLUvQBb,Khushboo Agarwal 2,10062,exact
|
||||
29631,royrogers,TYDGVBNC,account_nCAKAgLxtPx5H68AJZMNUA,Roy Rogers,10065,exact
|
||||
29632,arturoprieto,1653APVN877,account_pR6sTHc4xvLqPfAZhJxrxd,Arturo Prieto,10069,exact
|
||||
29633,ericamorris,E16488VN387,account_gG5uDHsz8FPiuknRCkpbHQ,Erica Morris,10071,exact
|
||||
29617,belindamillener,Uiyu7280,account_mXx2EoT7dcv2am6asSEJFr,Belinda Millener,10032,exact
|
||||
29618,kailynnbarnfield,HAkuguuvoy1,account_hVh2CveE2tBqctZhpLX5Nf,Kailynn Barnfield,10037,exact
|
||||
29619,thomasgraham,YUiygiiu4,account_fETWiC2bAqbb7hkQ5UvKjj,Thomas Graham,10040,exact
|
||||
27315,debravega,RCG8618BDUMSR,account_fbgziTjDnsrjH4aA2hMykS,Debra Vega,112,exact
|
||||
29582,davidlanman,2BMMRYQ2PHEA,account_u9P7hnf3FR5yqm7FFyCnrP,David Lanman,2486,exact
|
||||
29583,anthonylongo,9MLG8HVME4J3,account_eq2Po3eJPoEyv6RvhhyBMA,Anthony Longo,2487,exact
|
||||
29584,konradwoelffer,BCQ8NRFVNA3R,account_7B7CchNkRbNa6LLxRBform,Konrad Woelffer,2488,exact
|
||||
29585,marthaflores,KG2QEG36348V,account_cdbWPX28Kv3YSaYUDf7zj1,Martha Flores,2489,exact
|
||||
29586,connorspicer,6U2BWJKGCX8G,account_pV5Vstq2xr42fru5zVB28F,Connor Spicer,2490,exact
|
||||
29588,korybiggsshop,JA4SXBGKHFUL,account_irdUq6W33yA7J9vpQ5t85q,Kory Biggs Shop,2492,exact
|
||||
29589,ednagriffin,AXA8EZEAN7DJ,account_nnSEFSX86bVogx8KsqANUP,Edna Griffin,2493,exact
|
||||
29590,richardrosson,9J5L6MEH4Y7Y,account_jL9tR5FgswV7FZwxH3U5Ex,Richard Rosson,2526,exact
|
||||
29603,allentaylor2,NCJW87FW8723,account_sEcueqC1ysh7Ne2pE9qbg2,Allen Taylor #2,10009,exact
|
||||
29604,alextovias,7VSgrVO1WX,account_1BvWee8L5krmWQsfVUqCdk,Alex Tovias,476,exact
|
||||
29605,mikecurrence,MKH23FG79C,account_gbzPYU8zHeCSV7E5c5eksc,Mike Currence,10011,exact
|
||||
29594,terryrector,QUPP83ZUUSGL,account_bHx8uSNfzCrYkD8JriK1jV,Terry Rector,2529,exact
|
||||
29595,donnacampbell,KYCNTWS3929N,account_4y4ZEDFYqQhjW99pPJyLnf,Donna Campbell,2530,exact
|
||||
29600,billmctee,Bdge6388M,account_qdzi3bYpEjEx7crLFY4xCw,Bill McTee,373,exact
|
||||
29531,daycor,U45YBPSARH7N,account_aZmcKqobMWGKhxagDdLCFA,Cathy Day,755,fuzzy(manual_override)
|
||||
29521,tiffanyyarley-olenak,98HTZ9Q8FARG,account_cwmjmXkrYeba8h8RGqLm6E,Tiffany Yarley-Olenak,2393,fuzzy(sequence: 0.95)
|
||||
29395,vanessagomez1,J5JEW3HEBVAF,account_gb82EhqTwbNWWEovPu4oKZ,Vanessa Gomez,2264,fuzzy(last+first: gomez+vanessa(fn=1.00))
|
||||
29611,brittannieredden1,TYFTUEZ7429,account_bB6RDmNpkzndVbSh9CvgaL,Brittannie Redden,10017,fuzzy(last+first: redden+brittannie(fn=1.00))
|
||||
29614,samanthatheis,kf6u8djigk,account_x46hMNq15qHmEvP6fNFdfm,Samatha Theis,10023,fuzzy(last+first: theis+samatha(fn=0.70))
|
||||
29216,wanxiaxong,BER4NEK9M7NA,account_tiy5YHD34KpwPzUTXyRVFJ,Wanxia Song,2077,fuzzy(sequence: 0.86)
|
||||
29215,bryangoulart,DTNQFE4CXSFX,account_9sksoKmcJGxqhz4M4aD169,Brian Goulart,2076,fuzzy(last+first: goulart+brian(fn=0.70))
|
||||
29602,tech,brussels-crucial-smashing,account_jUFnZ52urgAMNgp9XhT4bs,Graham McIntire,1,fuzzy(manual_override)
|
||||
28935,chrislewis1,V9DS4E4Y7UTT,account_osB3NhyGdoWJRtpL5X2bfD,chris lewis,1787,fuzzy(last+first: lewis+chris(fn=1.00))
|
||||
28917,crankkeith,kcrank10615,account_iSuzVkNmem52NdXXh1Savu,Keith Crank,209,fuzzy(last+first: crank+keith(fn=1.00))
|
||||
28703,grahammcintire2,U5Y3hA3g*14L,account_jUFnZ52urgAMNgp9XhT4bs,Graham McIntire,1,fuzzy(last+first: mcintire+graham(fn=1.00))
|
||||
28702,chrissyeagle2,NJPCGPBNFB,account_3uu7k4euycmKnZii9DQAj2,Chrissy Eagle,74,fuzzy(last+first: eagle+chrissy(fn=1.00))
|
||||
28671,melodymccarty,U3WLEGEB,account_18HG9hdwwtZM83J9kyGMs6,Melody McCarthy,1397,fuzzy(sequence: 0.93)
|
||||
28642,barbihardin,ZENETJ75TEVQ,account_bb7iRuPixxutKZxnURfK5U,James Hardin,1475,fuzzy(manual_override)
|
||||
28628,jackworthy,2VUR7AAFWZZQ,account_hgoipVYXydD1yVSXTD9QGP,John Worthy,1461,fuzzy(last+first: worthy+john(fn=0.70))
|
||||
28542,michaelray2,jjPgDcotL6rtY,account_8Rh7edwTjNBYw9FJSq4WRT,Michael Ray,379,fuzzy(last+first: ray+michael(fn=1.00))
|
||||
28458,kennethcampbell2,V5TKW8L6RXFF,account_jF69QnP5j9FtfLgdAiUKfE,Kenneth D. Campbell,213,fuzzy(last+first: campbell+kenneth d(fn=1.00))
|
||||
28296,cinthiapereira1,9WSGXM9LBXGZ,account_57mDq22QWRV8tdPvk74Uvj,Cinthia Pereira,1102,fuzzy(last+first: pereira+cinthia(fn=1.00))
|
||||
28107,jacquelinewilder,HEY36LUGYCUQ,account_hHa9Z64B9okZ3yccQP9WpR,Jacquelin Wilder,892,fuzzy(last+first: wilder+jacquelin(fn=1.00))
|
||||
27939,reynamoore,R92nbskba7iM,account_k8gD8YGUQzwWCE7JT9EfYc,Rebekah Moore,386,fuzzy(last+first: moore+rebekah(fn=0.70))
|
||||
27912,blancadiaz,B548gdu55D,account_ktdNSpKRV3ja7RMi7pZRBB,Balnca Diaz,433,fuzzy(last+first: diaz+balnca(fn=0.70))
|
||||
27838,consueloluna1830,C8736gfd0,account_jw16PcKtprHpPkSAEhvsaN,Consuelo Luna,81,fuzzy(last+first: luna+consuelo(fn=1.00))
|
||||
27781,pambanschbach,Q2p68#*9vwF2,account_6hGXtJ7RV7mqZYfd5AyE1f,Pam Bansbach,383,fuzzy(sequence: 0.88)
|
||||
27639,choonpang,CP2143855677cp,account_o7aKk2FGKJAcmrXxMfUCpX,Geok Choon Pang,146,fuzzy(last+first: pang+geok choon(fn=1.00))
|
||||
27618,tammieventris,DR45QC74M,account_fMQ6qiwkPFWP8a86exFw4A,Terry Ventris,340,fuzzy(last+first: ventris+terry(fn=0.70))
|
||||
27579,donnance,9727346814,account_s9ZW1FpS3wkDoh31CjU1Zw,Dana Nance,89,fuzzy(last+first: nance+dana(fn=0.70))
|
||||
27501,jonnytaylor,Zb6677&4!yky,account_1fDruGS6CFTBUCGuzVZYTG,Johnny Taylor,190,fuzzy(last+first: taylor+johnny(fn=0.70))
|
||||
27436,clayrobertson2,C2147288546R,account_jgtX7TysTqcobVVBtSZEc2,Clay Robertson,77,fuzzy(last+first: robertson+clay(fn=1.00))
|
||||
27417,donniecampbell,6a2671bc0c1,account_4ww28eUsFRv8Yh5RkWe9cz,Danny Campbell,92,fuzzy(last+first: campbell+danny(fn=0.70))
|
||||
27418,alanwyatt,i1412r53MYr,account_2cnVCpSsYocCYpMEwwBBrY,Allen Wyatt,27,fuzzy(last+first: wyatt+allen(fn=0.70))
|
||||
29620,sayedahaque,YR4Sytbu,account_4hoTCjwTatthCg7zp2Cnfe,Syeda Haque,10048,fuzzy(last+first: haque+syeda(fn=0.70))
|
||||
29554,marcuspatton,GEUXX27VLZXK,account_dxY6AZnLdFUWup8Sf6XER1,Marcus Patton,2458,ambiguous_resolved(lowest_id)
|
||||
29606,mariacastanon,iu297gkid9,account_qh8bFPvWzyAqHqwHMDkThW,Maria Castanon,10007,ambiguous_resolved(lowest_id)
|
||||
28800,kennethcampbell,!9727342446!,account_jF69QnP5j9FtfLgdAiUKfE,Kenneth D. Campbell,213,ambiguous_resolved(lowest_id)
|
||||
28358,stephenday,MSVGQ8X38YLN,account_j1UFX8wqzorqSetUje5dTJ,Stephen Day,1168,ambiguous_resolved(lowest_id)
|
||||
27404,grahammcintire,U5Y3hA3g*14L,account_jUFnZ52urgAMNgp9XhT4bs,Graham McIntire,1,ambiguous_resolved(lowest_id)
|
||||
29630,sriahobilamuth,RTCESW24,account_7PgSr8dVuafybJdrXND3V9,Sri Ahobilamuth,113,ambiguous_resolved(lowest_id)
|
||||
29524,chandparvathaneni,TK4QA3XM5XK5,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29358,radiantlifeministries,12FDIUNF5L7vM,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29296,midvalleyconcrete,BD58JYT2PJ6A,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29244,janiscable,JHC7U554JBTR,,,,"still_unmatched(best: last+weakfirst: cable+gary w(fn=0.11), score: 0.611)"
|
||||
29150,donwilhelmus,2V4NEL87RM39,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29135,kavalleriefarm,8DFNNTPBPZGY,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29077,kellygarza,4696591662,,,,"still_unmatched(best: last+weakfirst: garza+esparanza(fn=0.42), score: 0.642)"
|
||||
29070,1stchoiceliving,YVWJWRPEVYNH,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28879,kimberlyrichards,7PQA6J8RPZ9Z,,,,"still_unmatched(best: last+weakfirst: kim+tae(fn=0.08), score: 0.608)"
|
||||
28599,ryanrodriguez,9DFYWJ47YWUP,,,,"still_unmatched(best: last+weakfirst: rodriguez+mike(fn=0.19), score: 0.619)"
|
||||
28460,saidaacosta,V29897X4,,,,"still_unmatched(best: last+weakfirst: acosta+alma(fn=0.21), score: 0.621)"
|
||||
28422,jackiehendricks,UQR5HGFCJ4XX,,,,"still_unmatched(best: last+weakfirst: hendricks+sue(fn=0.09), score: 0.609)"
|
||||
28400,bonniestone,BH8BV44TTWUU,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28336,buddyswan,N7XUYUD7J9SD,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28268,alberto,TICOGUILLO,,,,"still_unmatched(best: , score: 0.0)"
|
||||
28213,krisdougherty,RWEH75UJ38,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27955,evlynrichter,FRQD738BGRC,,,,"still_unmatched(best: last+weakfirst: richter+brent(fn=0.19), score: 0.619)"
|
||||
27793,branchrvpark,XfKxVZIKmm,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29601,kimberlyrichards2,K84f7r10GT108,,,,"still_unmatched(best: last+weakfirst: kim+tae(fn=0.08), score: 0.608)"
|
||||
27755,gordonhamilton,c3495Rpuq5Sh,,,,"still_unmatched(best: last+weakfirst: hamilton+sheryl f(fn=0.16), score: 0.616)"
|
||||
27709,sensibleheatsystems,SHQWERY23,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27704,lambandlion,LL9727363567ll,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27625,mattbud,kjklfda79sd,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27621,richardhill,RH9729788124rh,,,,no_match
|
||||
27489,jenniferreed,683P7V7R,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27482,irvinbarojas,yDeEJzYY08,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27463,dennispereyra,82s62kd9XHhd,,,,"still_unmatched(best: , score: 0.0)"
|
||||
27441,samanthasmith,22jmR9X#93j5,,,,"still_unmatched(best: last+weakfirst: smith+kathy(fn=0.27), score: 0.627)"
|
||||
27408,penneywarner,b4h53N6c#5wo,,,,"still_unmatched(best: , score: 0.0)"
|
||||
29626,karengreen,UTKCYI674,,,,"still_unmatched(best: last+weakfirst: green+dominique(fn=0.17), score: 0.617)"
|
||||
|
68
gaiia/radius_gaiia_unmatched.csv
Normal file
68
gaiia/radius_gaiia_unmatched.csv
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
radius_id,username,password,gaiia_id,gaiia_name,gaiia_readable_id,match_type
|
||||
29554,marcuspatton,GEUXX27VLZXK,,"AMBIGUOUS: Marcus Patton, Marcus Patton",,ambiguous
|
||||
29524,chandparvathaneni,TK4QA3XM5XK5,,,,no_match
|
||||
29521,tiffanyyarley-olenak,98HTZ9Q8FARG,,,,no_match
|
||||
29606,mariacastanon,iu297gkid9,,"AMBIGUOUS: Maria Castanon, Maria Castanon",,ambiguous
|
||||
29395,vanessagomez1,J5JEW3HEBVAF,,,,no_match
|
||||
29611,brittannieredden1,TYFTUEZ7429,,,,no_match
|
||||
29614,samanthatheis,kf6u8djigk,,,,no_match
|
||||
29358,radiantlifeministries,12FDIUNF5L7vM,,,,no_match
|
||||
29296,midvalleyconcrete,BD58JYT2PJ6A,,,,no_match
|
||||
29244,janiscable,JHC7U554JBTR,,,,no_match
|
||||
29216,wanxiaxong,BER4NEK9M7NA,,,,no_match
|
||||
29215,bryangoulart,DTNQFE4CXSFX,,,,no_match
|
||||
29150,donwilhelmus,2V4NEL87RM39,,,,no_match
|
||||
29135,kavalleriefarm,8DFNNTPBPZGY,,,,no_match
|
||||
29077,kellygarza,4696591662,,,,no_match
|
||||
29070,1stchoiceliving,YVWJWRPEVYNH,,,,no_match
|
||||
29602,tech,brussels-crucial-smashing,,,,no_match
|
||||
28935,chrislewis1,V9DS4E4Y7UTT,,,,no_match
|
||||
28917,crankkeith,kcrank10615,,,,no_match
|
||||
28879,kimberlyrichards,7PQA6J8RPZ9Z,,,,no_match
|
||||
28800,kennethcampbell,!9727342446!,,"AMBIGUOUS: Kenneth D. Campbell, Kenneth Campbell",,ambiguous
|
||||
28703,grahammcintire2,U5Y3hA3g*14L,,,,no_match
|
||||
28702,chrissyeagle2,NJPCGPBNFB,,,,no_match
|
||||
28671,melodymccarty,U3WLEGEB,,,,no_match
|
||||
28642,barbihardin,ZENETJ75TEVQ,,,,no_match
|
||||
28628,jackworthy,2VUR7AAFWZZQ,,,,no_match
|
||||
28599,ryanrodriguez,9DFYWJ47YWUP,,,,no_match
|
||||
28542,michaelray2,jjPgDcotL6rtY,,,,no_match
|
||||
28460,saidaacosta,V29897X4,,,,no_match
|
||||
28458,kennethcampbell2,V5TKW8L6RXFF,,,,no_match
|
||||
28422,jackiehendricks,UQR5HGFCJ4XX,,,,no_match
|
||||
28400,bonniestone,BH8BV44TTWUU,,,,no_match
|
||||
28358,stephenday,MSVGQ8X38YLN,,"AMBIGUOUS: Stephen Day, Stephen Day",,ambiguous
|
||||
28336,buddyswan,N7XUYUD7J9SD,,,,no_match
|
||||
28296,cinthiapereira1,9WSGXM9LBXGZ,,,,no_match
|
||||
28268,alberto,TICOGUILLO,,,,no_match
|
||||
29531,daycor,U45YBPSARH7N,,,,no_match
|
||||
29630,sriahobilamuth,RTCESW24,,"AMBIGUOUS: Sri Ahobilamuth, Sri Ahobilamuth",,ambiguous
|
||||
27408,penneywarner,b4h53N6c#5wo,,,,no_match
|
||||
29620,sayedahaque,YR4Sytbu,,,,no_match
|
||||
29626,karengreen,UTKCYI674,,,,no_match
|
||||
27404,grahammcintire,U5Y3hA3g*14L,,"AMBIGUOUS: Graham McIntire, Graham McIntire, Graham McIntire",,ambiguous
|
||||
27417,donniecampbell,6a2671bc0c1,,,,no_match
|
||||
27418,alanwyatt,i1412r53MYr,,,,no_match
|
||||
27441,samanthasmith,22jmR9X#93j5,,,,no_match
|
||||
27436,clayrobertson2,C2147288546R,,,,no_match
|
||||
27489,jenniferreed,683P7V7R,,,,no_match
|
||||
27501,jonnytaylor,Zb6677&4!yky,,,,no_match
|
||||
27482,irvinbarojas,yDeEJzYY08,,,,no_match
|
||||
27463,dennispereyra,82s62kd9XHhd,,,,no_match
|
||||
27579,donnance,9727346814,,,,no_match
|
||||
27838,consueloluna1830,C8736gfd0,,,,no_match
|
||||
27912,blancadiaz,B548gdu55D,,,,no_match
|
||||
27709,sensibleheatsystems,SHQWERY23,,,,no_match
|
||||
27704,lambandlion,LL9727363567ll,,,,no_match
|
||||
27625,mattbud,kjklfda79sd,,,,no_match
|
||||
27639,choonpang,CP2143855677cp,,,,no_match
|
||||
127621,richardhill,RH9729788124rh,,,,no_match
|
||||
27618,tammieventris,DR45QC74M,,,,no_match
|
||||
27955,evlynrichter,FRQD738BGRC,,,,no_match
|
||||
27939,reynamoore,R92nbskba7iM,,,,no_match
|
||||
27755,gordonhamilton,c3495Rpuq5Sh,,,,no_match
|
||||
27793,branchrvpark,XfKxVZIKmm,,,,no_match
|
||||
27781,pambanschbach,Q2p68#*9vwF2,,,,no_match
|
||||
29601,kimberlyrichards2,K84f7r10GT108,,,,no_match
|
||||
28213,krisdougherty,RWEH75UJ38,,,,no_match
|
||||
28107,jacquelinewilder,HEY36LUGYCUQ,,,,no_match
|
||||
|
2687
gaiia/radius_usernames.json
Normal file
2687
gaiia/radius_usernames.json
Normal file
File diff suppressed because it is too large
Load diff
415
gaiia/radius_users.txt
Normal file
415
gaiia/radius_users.txt
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
| 29581 | joseortiz | Cleartext-Password | := | J2WEYT7782UJ |
|
||||
| 29578 | perlachavez2 | Cleartext-Password | := | U4BBTBMCJZST |
|
||||
| 29575 | thomashernandez | Cleartext-Password | := | X6BZLA7SC3XM |
|
||||
| 29572 | williamarmstead | Cleartext-Password | := | SAQ4XEKXDC58 |
|
||||
| 29570 | julierose | Cleartext-Password | := | MLM8R2WAGY52 |
|
||||
| 29571 | derrickmccausland | Cleartext-Password | := | ETNLKZHACGF7 |
|
||||
| 29567 | sherrifredrick | Cleartext-Password | := | 7P52BVMTSNN6 |
|
||||
| 29565 | shelbyburris | Cleartext-Password | := | 3YAL9DWFZUPT |
|
||||
| 29564 | priscillacrenshaw | Cleartext-Password | := | AXBDLXSGXMLR |
|
||||
| 29561 | korybiggs | Cleartext-Password | := | 4FJC7DXAW5RV |
|
||||
| 29563 | kristinjimenez | Cleartext-Password | := | 9FAYXMRDU69T |
|
||||
| 29558 | jessicaweddle | Cleartext-Password | := | VV96G36AEEDA |
|
||||
| 29557 | yolandamedrano | Cleartext-Password | := | R948UL4KZRA4 |
|
||||
| 29555 | williambowland | Cleartext-Password | := | K7HYNWGE25XX |
|
||||
| 29554 | marcuspatton | Cleartext-Password | := | GEUXX27VLZXK |
|
||||
| 29553 | shacaciabillings | Cleartext-Password | := | 8AZLJCDFYFYV |
|
||||
| 29552 | guadalupelugo | Cleartext-Password | := | DQG8XCMFMVH5 |
|
||||
| 29551 | brandonhardesty | Cleartext-Password | := | KMRHVPEXBEZ8 |
|
||||
| 29550 | nancyavellaneda | Cleartext-Password | := | CXATYV7NGZN2 |
|
||||
| 29549 | matthewgoodwin | Cleartext-Password | := | VSPM7N9UNU6Y |
|
||||
| 29545 | donmckinney | Cleartext-Password | := | C6AQ6UVD6R7R |
|
||||
| 29544 | natashaelmore | Cleartext-Password | := | 8G5QJ8R7MK8Q |
|
||||
| 29543 | shamsbashir | Cleartext-Password | := | WLBGY4JMN4VA |
|
||||
| 29541 | douglasglover | Cleartext-Password | := | 9Y6H9X3HCG3D |
|
||||
| 29538 | carolstrickland | Cleartext-Password | := | 547P6AQ8RCD4 |
|
||||
| 29537 | carmenlopez | Cleartext-Password | := | TPLND3H2FWTQ |
|
||||
| 29534 | johnlooper | Cleartext-Password | := | ZPL8LRY2TGRH |
|
||||
| 29535 | davidroesch | Cleartext-Password | := | ZHB2BS968DTU |
|
||||
| 29531 | daycor | Cleartext-Password | := | U45YBPSARH7N |
|
||||
| 29530 | derekrodriguez | Cleartext-Password | := | AP7Z594DMR7E |
|
||||
| 29524 | chandparvathaneni | Cleartext-Password | := | TK4QA3XM5XK5 |
|
||||
| 29522 | joshuasoliz | Cleartext-Password | := | PE7MHRZWUEQM |
|
||||
| 29521 | tiffanyyarley-olenak | Cleartext-Password | := | 98HTZ9Q8FARG |
|
||||
| 29514 | ericbarrett | Cleartext-Password | := | 5S2CV9FEFMKG |
|
||||
| 29513 | marysmelser | Cleartext-Password | := | ZS74NS5BBPX3 |
|
||||
| 29506 | nicolemaenn | Cleartext-Password | := | B7KS27WL5WSN |
|
||||
| 29503 | yolandajudge | Cleartext-Password | := | 6V8RLNK75LM8 |
|
||||
| 29501 | craighovde | Cleartext-Password | := | AVZXWBX8GQTC |
|
||||
| 29498 | joselucas | Cleartext-Password | := | ZHMW9TE8QHRX |
|
||||
| 29488 | douggarber | Cleartext-Password | := | WXP9J5SRJWEJ |
|
||||
| 29482 | carmencleghorn | Cleartext-Password | := | VH3CBTJZAJ2Y |
|
||||
| 29472 | rubenreyez | Cleartext-Password | := | 66384Y7B4WR4 |
|
||||
| 29464 | tiffanystewart | Cleartext-Password | := | 3EGVCS6RMF3Z |
|
||||
| 29449 | dejadodson | Cleartext-Password | := | FLR4DJHPX6TG |
|
||||
| 29447 | coreyball | Cleartext-Password | := | 3JAUWZNAR9MB |
|
||||
| 29442 | toniyoung | Cleartext-Password | := | RJ24VTRM7JA9 |
|
||||
| 29434 | melanieweddle | Cleartext-Password | := | XQ5L7PUM9RP6 |
|
||||
| 29431 | zackknuckey | Cleartext-Password | := | VP5CCX8LTE47 |
|
||||
| 29425 | christinehamparyan | Cleartext-Password | := | WEYX9R5P7J5L |
|
||||
| 29422 | joespeciale | Cleartext-Password | := | UH6ZCM9WLGRQ |
|
||||
| 29420 | rogerbatt | Cleartext-Password | := | KGDJZ7V66QQK |
|
||||
| 29419 | kalebjames | Cleartext-Password | := | KMQDGPD5XB6Z |
|
||||
| 29416 | stevemolina | Cleartext-Password | := | BLLHWPY9RCTC |
|
||||
| 29414 | mariatrejo | Cleartext-Password | := | EYPWCQKKWYZH |
|
||||
| 29410 | kenhall | Cleartext-Password | := | LX897BGJNMK5 |
|
||||
| 29407 | deewilliams | Cleartext-Password | := | R8AGX3E8WAHN |
|
||||
| 29406 | johnvayo | Cleartext-Password | := | DJJNUEEHGAW5 |
|
||||
| 29398 | anthonythompson | Cleartext-Password | := | WB4E4MPJVHTB |
|
||||
| 29608 | stevecombest | ClearText-Password | := | STVN23552Wt |
|
||||
| 29606 | mariacastanon | ClearText-Password | := | iu297gkid9 |
|
||||
| 29395 | vanessagomez1 | Cleartext-Password | := | J5JEW3HEBVAF |
|
||||
| 29607 | luisvelira | ClearText-Password | := | uygo875491! |
|
||||
| 29609 | keithtucker | ClearText-Password | := | 14FYJSNUU48 |
|
||||
| 29610 | angelatrevino | ClearText-Password | := | KJGU39565 |
|
||||
| 29611 | brittannieredden1 | ClearText-Password | := | TYFTUEZ7429 |
|
||||
| 29612 | amymontelongo | ClearText-Password | := | ig76f7fuvu |
|
||||
| 29613 | michaelasmith | ClearText-Password | := | MS21353GHY |
|
||||
| 29614 | samanthatheis | ClearText-Password | := | kf6u8djigk |
|
||||
| 29615 | janisstewart | ClearText-Password | := | JD834HCUW1C |
|
||||
| 29616 | irenegaribay | ClearText-Password | := | uky75dkc |
|
||||
| 29383 | leonardocoronel | Cleartext-Password | := | TXPC494 |
|
||||
| 29374 | alejandrolimon | Cleartext-Password | := | MM4BSQS7FRTD |
|
||||
| 29368 | crystalharney | Cleartext-Password | := | A7W26H834WLJ |
|
||||
| 29358 | radiantlifeministries | Cleartext-Password | := | 12FDIUNF5L7vM |
|
||||
| 29355 | olgagutierrez | Cleartext-Password | := | WERWRMUDBZ85 |
|
||||
| 29353 | greghummel | Cleartext-Password | := | JV84HSVAK6XR |
|
||||
| 29349 | bettymitchell | Cleartext-Password | := | 8CHHCNBWQLRV |
|
||||
| 29341 | wandadavis | Cleartext-Password | := | JXQXXZ9MKFX6 |
|
||||
| 29338 | scottanderson | Cleartext-Password | := | RJ49A43SG3RA |
|
||||
| 29335 | jenniferboon | Cleartext-Password | := | 28ESU8ELVELP |
|
||||
| 29331 | marialopez | Cleartext-Password | := | P3FNSPT7MEYM |
|
||||
| 29329 | cynthiasandlin | Cleartext-Password | := | MCDTLMVFQXAV |
|
||||
| 29328 | bethanybell | Cleartext-Password | := | 3UUC5X27PETS |
|
||||
| 29323 | garrettojeda | Cleartext-Password | := | U5PRQYZE2MM3 |
|
||||
| 29325 | rayschaak | Cleartext-Password | := | XSNLP62EK6VZ |
|
||||
| 29327 | carlaswearingen | Cleartext-Password | := | E6DQ4B2T9JZD |
|
||||
| 29320 | lesliebewley | Cleartext-Password | := | 55KFSJMEDYLK |
|
||||
| 29317 | delainawaite | Cleartext-Password | := | EM7TWHUS4SYU |
|
||||
| 29307 | esparanzagarza | Cleartext-Password | := | VLL9ZNPRSTG5 |
|
||||
| 29296 | midvalleyconcrete | Cleartext-Password | := | BD58JYT2PJ6A |
|
||||
| 29273 | glendabeauchamp | Cleartext-Password | := | RKA3J8WSPYJP |
|
||||
| 29256 | glindarichter | Cleartext-Password | := | VXMLMDAFLNJ3 |
|
||||
| 29251 | nhumorrison | Cleartext-Password | := | EC32VDFKB9CB |
|
||||
| 29245 | brittanyworley | Cleartext-Password | := | NBKYERRBSBH4 |
|
||||
| 29244 | janiscable | Cleartext-Password | := | JHC7U554JBTR |
|
||||
| 29243 | dustynfisher | Cleartext-Password | := | XASFU3DBPZ5M |
|
||||
| 29237 | stephenbeegle | Cleartext-Password | := | RU5GZVTVACRC |
|
||||
| 29229 | roseanndellavalle | Cleartext-Password | := | 5GAF6JHUWWYP |
|
||||
| 29231 | duanewright | Cleartext-Password | := | VXK4FBLVFE7F |
|
||||
| 29222 | pablohernandez | Cleartext-Password | := | P3YB6A4JGEDF |
|
||||
| 29217 | pavelavanesov | Cleartext-Password | := | KP8ZSGC2DG2U |
|
||||
| 29216 | wanxiaxong | Cleartext-Password | := | BER4NEK9M7NA |
|
||||
| 29215 | bryangoulart | Cleartext-Password | := | DTNQFE4CXSFX |
|
||||
| 29204 | sandrahoughton | Cleartext-Password | := | 5XR4QMPBXVWY |
|
||||
| 29203 | adamstaeben | Cleartext-Password | := | GP7RANJ8UCYP |
|
||||
| 29190 | russmott | Cleartext-Password | := | J8ZN888UQSLR |
|
||||
| 29189 | karenstewart | Cleartext-Password | := | JSKTFAJ2JYDX |
|
||||
| 29185 | heatherwomack | Cleartext-Password | := | 89W7S5Q7UAHP |
|
||||
| 29183 | wyndijames | Cleartext-Password | := | CPSDNRQU95HJ |
|
||||
| 29182 | angelicacuayahuitl | Cleartext-Password | := | VK8PZW3LK5F3 |
|
||||
| 29181 | chasewilliams | Cleartext-Password | := | W6AMPQEPY3BC |
|
||||
| 29176 | kevinarana | Cleartext-Password | := | JAJYSEG75UZS |
|
||||
| 29166 | chrisclayton | Cleartext-Password | := | BFJ462PLHJFV |
|
||||
| 29162 | billyhorton | Cleartext-Password | := | MPTX573ZUYYG |
|
||||
| 29151 | chisediquezada | Cleartext-Password | := | RJBYQ2NUB829 |
|
||||
| 29150 | donwilhelmus | Cleartext-Password | := | 2V4NEL87RM39 |
|
||||
| 29147 | angelmerlo | Cleartext-Password | := | EWWAPXN9Z2YS |
|
||||
| 29135 | kavalleriefarm | Cleartext-Password | := | 8DFNNTPBPZGY |
|
||||
| 29113 | kerryblack | Cleartext-Password | := | 9D5S9ZD2FCBV |
|
||||
| 29110 | cliffordjennings | Cleartext-Password | := | 5GC7M65H9VGT |
|
||||
| 29098 | carlakimberling | Cleartext-Password | := | SS4KRJYKTV7B |
|
||||
| 29088 | richardconklin | Cleartext-Password | := | WEUNG5H3K8BB |
|
||||
| 29089 | leandrabeshea | Cleartext-Password | := | 7V8BZU4G83VF |
|
||||
| 29077 | kellygarza | Cleartext-Password | := | 4696591662 |
|
||||
| 29070 | 1stchoiceliving | Cleartext-Password | := | YVWJWRPEVYNH |
|
||||
| 29067 | robertfinch | Cleartext-Password | := | D7FMTT455GBB |
|
||||
| 29058 | ericcoffman | Cleartext-Password | := | MMEBXQYLZWNU |
|
||||
| 29050 | nathanaelfinch | Cleartext-Password | := | JVNC68FV7N6B |
|
||||
| 29047 | gabrielasereno | Cleartext-Password | := | KCH82WCRA2YR |
|
||||
| 29045 | georginacovarrubias | Cleartext-Password | := | 8QT57NUV8C7R |
|
||||
| 29035 | thomascline | Cleartext-Password | := | E523BKVU5MJP |
|
||||
| 29034 | susanlewis | Cleartext-Password | := | R7TZFZEGLNRW |
|
||||
| 29025 | tammywelborn | Cleartext-Password | := | RMC482WNBS7 |
|
||||
| 29023 | haleymuela | Cleartext-Password | := | BS7X3DTKW8TH |
|
||||
| 29018 | christelles | Cleartext-Password | := | WL2TKLFG8G2H |
|
||||
| 29017 | mauricioantonio | Cleartext-Password | := | 6QJW7RAPDBWB |
|
||||
| 29013 | vincentlimon | Cleartext-Password | := | YDDXKFABUZY7 |
|
||||
| 29602 | tech | ClearText-Password | := | brussels-crucial-smashing |
|
||||
| 29634 | jeffreyharder | ClearText-Password | := | YUV565D67RT |
|
||||
| 29635 | pablomartinez | ClearText-Password | := | 2766581BER |
|
||||
| 29636 | krystalmendez | ClearText-Password | := | 6FTCKU6S56 |
|
||||
| 29637 | davidvandagriff | Cleartext-Password | := | UTRC53865F9 |
|
||||
| 29638 | carolynwalker | Cleartext-Password | := | trjxtyx75! |
|
||||
| 28979 | claygilbert | Cleartext-Password | := | 3E6XFDHXCAG7 |
|
||||
| 28978 | jmichaelculverhouse | Cleartext-Password | := | 2147099521 |
|
||||
| 28971 | diegosereno | Cleartext-Password | := | 2CE9F5YSPQHX |
|
||||
| 28970 | ashleysmith | Cleartext-Password | := | F8D3FVCZB7PD |
|
||||
| 28954 | dougstowe | Cleartext-Password | := | 5D35LFD6GEAZ |
|
||||
| 28936 | timbronschidle | ClearText-Password | := | 3ZVLCWSAE3EW1 |
|
||||
| 28935 | chrislewis1 | Cleartext-Password | := | V9DS4E4Y7UTT |
|
||||
| 28928 | cynthiajones | Cleartext-Password | := | KC7ESYHEZGNR |
|
||||
| 28917 | crankkeith | Cleartext-Password | := | kcrank10615 |
|
||||
| 28879 | kimberlyrichards | Cleartext-Password | := | 7PQA6J8RPZ9Z |
|
||||
| 28867 | bobbymack | Cleartext-Password | := | UDUBTCXXF8VV |
|
||||
| 28848 | americatrejo | Cleartext-Password | := | 3B63TLTT9WE4 |
|
||||
| 28832 | tjbanschbach | Cleartext-Password | := | 8WTWTXACGG5N |
|
||||
| 28811 | luiscabrera | Cleartext-Password | := | RWUQ94XT9A9Z |
|
||||
| 28810 | rosahernandez | Cleartext-Password | := | JSGUXKWEMSVN |
|
||||
| 28807 | carlosgomez | Cleartext-Password | := | J22RS7F3LGG2 |
|
||||
| 28800 | kennethcampbell | Cleartext-Password | := | !9727342446! |
|
||||
| 28763 | jeridrutledge | Cleartext-Password | := | GJ3CZTRJJW2M |
|
||||
| 28748 | timthomas | Cleartext-Password | := | NY223RQJD7PN |
|
||||
| 28715 | carolbates | Cleartext-Password | := | J3UBUCMYDX64 |
|
||||
| 28710 | shirleyelmore | Cleartext-Password | := | D8Y64N9L4R9W |
|
||||
| 28703 | grahammcintire2 | Cleartext-Password | := | U5Y3hA3g*14L |
|
||||
| 28702 | chrissyeagle2 | Cleartext-Password | := | NJPCGPBNFB |
|
||||
| 28698 | swedlund | Cleartext-Password | := | swedlund494 |
|
||||
| 28695 | wendysanders | Cleartext-Password | := | RYG9L43NWDZV |
|
||||
| 28693 | robbymccollom | Cleartext-Password | := | RMC482WNBS7 |
|
||||
| 28671 | melodymccarty | Cleartext-Password | := | U3WLEGEB |
|
||||
| 28664 | heatherbrister2 | Cleartext-Password | := | KK37V8W9ZD9Z |
|
||||
| 28663 | ryanlloyd | Cleartext-Password | := | HWEMKNWX55RF |
|
||||
| 28661 | amyrodriguez | Cleartext-Password | := | WX3QRT2U6L4X |
|
||||
| 28660 | thecountrycutter | Cleartext-Password | := | YXpScFIneePm |
|
||||
| 28659 | bradwilson | Cleartext-Password | := | ZFAXA9AK63AH |
|
||||
| 28654 | edrater | Cleartext-Password | := | FRY4823N |
|
||||
| 28642 | barbihardin | Cleartext-Password | := | ZENETJ75TEVQ |
|
||||
| 28637 | vikyacosta | Cleartext-Password | := | Z4SMV49SAH72 |
|
||||
| 28633 | terrimack | Cleartext-Password | := | B9HNTSN7ASQ4 |
|
||||
| 28628 | jackworthy | Cleartext-Password | := | 2VUR7AAFWZZQ |
|
||||
| 28617 | luisarellano | Cleartext-Password | := | GVNWBQMM3S7U |
|
||||
| 28609 | dorisavalos | Cleartext-Password | := | DLKMJS88AF2W |
|
||||
| 28599 | ryanrodriguez | Cleartext-Password | := | 9DFYWJ47YWUP |
|
||||
| 28597 | jackierollier | Cleartext-Password | := | TSFNN8DVDSPR |
|
||||
| 28588 | charlesmccreary | Cleartext-Password | := | 88J6XS6TXRMA |
|
||||
| 28548 | jamessmith | Cleartext-Password | := | LRVU6RVG5SP8 |
|
||||
| 28546 | davidwhitefoot | Cleartext-Password | := | PYHTZMHJU8R8- |
|
||||
| 28542 | michaelray2 | Cleartext-Password | := | jjPgDcotL6rtY |
|
||||
| 28536 | patriciavasquez | Cleartext-Password | := | P88256487V |
|
||||
| 28535 | adrianmcdaniel | Cleartext-Password | := | U4TGDH2PSAB4 |
|
||||
| 28526 | justinvoga | Cleartext-Password | := | URHVCX7SFSFU |
|
||||
| 28518 | jenniferlittle | Cleartext-Password | := | 8EAUUDQPXSQX |
|
||||
| 28510 | bradslate | Cleartext-Password | := | AF4KVQ2P44M7 |
|
||||
| 28494 | irisdelira | Cleartext-Password | := | L6XGQA583DG6 |
|
||||
| 28491 | richardbarragan | Cleartext-Password | := | WJBS86MMJBFH |
|
||||
| 28476 | jensenhall | Cleartext-Password | := | F8XM9U8SC6LL |
|
||||
| 28466 | paulcomella | Cleartext-Password | := | YTZDMBZCMPX4 |
|
||||
| 28460 | saidaacosta | Cleartext-Password | := | V29897X4 |
|
||||
| 28458 | kennethcampbell2 | Cleartext-Password | := | V5TKW8L6RXFF |
|
||||
| 28449 | amberkrings | Cleartext-Password | := | 5NWBR3JLV6N8 |
|
||||
| 28438 | mauriciosoto | Cleartext-Password | := | DJ7YP7W7AA8M |
|
||||
| 28435 | jimcrank | Cleartext-Password | := | PLA7XNX2F4Y3 |
|
||||
| 28425 | summerbeazley | Cleartext-Password | := | D4S4YRB8Y3KA |
|
||||
| 28426 | davidarmstrong | Cleartext-Password | := | MPEZGG53KQSZ |
|
||||
| 28422 | jackiehendricks | Cleartext-Password | := | UQR5HGFCJ4XX |
|
||||
| 28400 | bonniestone | Cleartext-Password | := | BH8BV44TTWUU |
|
||||
| 28395 | stevenspurgers | Cleartext-Password | := | YS5Q785J2HGZ |
|
||||
| 28388 | connercoleman | Cleartext-Password | := | 6108RANDOMREDDOG |
|
||||
| 28367 | judithfierro | Cleartext-Password | := | FUZ33LB6SFFC |
|
||||
| 28359 | tonyasipes | Cleartext-Password | := | N5VEZR8Q5M86 |
|
||||
| 28358 | stephenday | Cleartext-Password | := | MSVGQ8X38YLN |
|
||||
| 28347 | kathysmith | Cleartext-Password | := | SJ53PSYCZLPR |
|
||||
| 28344 | cherieeshelman | Cleartext-Password | := | BRUV99PN6Y7L |
|
||||
| 28336 | buddyswan | Cleartext-Password | := | N7XUYUD7J9SD |
|
||||
| 28296 | cinthiapereira1 | Cleartext-Password | := | 9WSGXM9LBXGZ |
|
||||
| 28289 | ronberger | Cleartext-Password | := | Ronb499H7ALW |
|
||||
| 28268 | alberto | Cleartext-Password | := | TICOGUILLO |
|
||||
| 28267 | sandracrouch | Cleartext-Password | := | V4N3764R5J |
|
||||
| 28263 | abbieandrews | Cleartext-Password | := | YQSJ499H7ALW |
|
||||
| 28253 | perlachavez | Cleartext-Password | := | ZWR9PXVFFYBS |
|
||||
| 28246 | susanking | Cleartext-Password | := | N2KUYLPDNXJP |
|
||||
| 28241 | terrybachran | Cleartext-Password | := | NG9VMH25LCTC |
|
||||
| 28240 | lanaygaunce | Cleartext-Password | := | MJCNZAJHK9H3 |
|
||||
| 28213 | krisdougherty | Cleartext-Password | := | RWEH75UJ38 |
|
||||
| 28190 | heatherbrister | Cleartext-Password | := | 6XPLC545G6HW |
|
||||
| 28184 | jenniferdunaway | Cleartext-Password | := | 343V5CT2R7HZ |
|
||||
| 28159 | elviraquezada | Cleartext-Password | := | HXAS29VRX33V |
|
||||
| 28154 | jordainpatton | Cleartext-Password | := | J8P4TPF7QS2A |
|
||||
| 28140 | mattkosarek | Cleartext-Password | := | RJ4BQUZJY |
|
||||
| 28117 | shannonclark | Cleartext-Password | := | F5XESMCJ |
|
||||
| 28107 | jacquelinewilder | Cleartext-Password | := | HEY36LUGYCUQ |
|
||||
| 28098 | kevincostanzo | Cleartext-Password | := | 244VGMVMH66D |
|
||||
| 28093 | kenpatrick | Cleartext-Password | := | V7U3XBAPTSV3 |
|
||||
| 28083 | briangallimore | Cleartext-Password | := | 39V285NX |
|
||||
| 28072 | amberprater | Cleartext-Password | := | RP42B7AYDLAP |
|
||||
| 28068 | marilynfowler | Cleartext-Password | := | MarilynVG72P8H |
|
||||
| 28065 | douglaswilson | Cleartext-Password | := | HP97HG9XPYC3 |
|
||||
| 28034 | terrygortney | Cleartext-Password | := | GQUGR3VJUXBR |
|
||||
| 28031 | gizellebutler | Cleartext-Password | := | HMZTX66RTPVX |
|
||||
| 28029 | bradgurney | Cleartext-Password | := | 7A6LRZWT82DX |
|
||||
| 28024 | darrylchavis | Cleartext-Password | := | TDGUUNXGMYRC |
|
||||
| 28025 | kathymazzola | Cleartext-Password | := | 5MVS8VUF9QL2 |
|
||||
| 27994 | austinwatkins | Cleartext-Password | := | S7M4UD8QUTDP |
|
||||
| 27988 | oscarrodriguez | Cleartext-Password | := | TGPCF3Y2ABXS |
|
||||
| 27986 | erinthompson | Cleartext-Password | := | 69TQZ797 |
|
||||
| 27983 | brianhardesty | Cleartext-Password | := | 8D4P34N8 |
|
||||
| 27976 | cathyday | Cleartext-Password | := | FAXMKENV8FCT |
|
||||
| 27956 | fredheckel | Cleartext-Password | := | HUVZSE8RGD65 |
|
||||
| 27955 | evlynrichter | Cleartext-Password | := | FRQD738BGRC |
|
||||
| 27949 | charlesboone | Cleartext-Password | := | Ccbn78wdfksB |
|
||||
| 27948 | rachelguzzardi | Cleartext-Password | := | R87wgerf8bsG |
|
||||
| 27939 | reynamoore | Cleartext-Password | := | R92nbskba7iM |
|
||||
| 27936 | juanalonzo | Cleartext-Password | := | 745GF0JK5!W |
|
||||
| 27930 | kristinamurphy | Cleartext-Password | := | oPXFrylqKf |
|
||||
| 27926 | johnnygoble | Cleartext-Password | := | J829fhf7G |
|
||||
| 27923 | keithbarber | Cleartext-Password | := | K73bvd54tB |
|
||||
| 27917 | doreengrubb | Cleartext-Password | := | DOR32SVT1234 |
|
||||
| 27916 | steveraia | Cleartext-Password | := | DRR648DFTMSE4 |
|
||||
| 27912 | blancadiaz | Cleartext-Password | := | B548gdu55D |
|
||||
| 27896 | twcowley | Cleartext-Password | := | TW486TW |
|
||||
| 27888 | joepatton | Cleartext-Password | := | L7luYzSKSu |
|
||||
| 27873 | timfisher | Cleartext-Password | := | Thd73gdf5eF |
|
||||
| 27847 | kileigheven | Cleartext-Password | := | K9872gdf8E |
|
||||
| 27838 | consueloluna1830 | Cleartext-Password | := | C8736gfd0 |
|
||||
| 27833 | deannecook | Cleartext-Password | := | Dc872cobnC |
|
||||
| 27830 | kacyharrison | Cleartext-Password | := | 7Ozr7el6K1 |
|
||||
| 27822 | milliganwater | Cleartext-Password | := | 8NjGMNsTXd |
|
||||
| 27813 | michaelnewby | Cleartext-Password | := | TM5M3HU877 |
|
||||
| 27808 | ladonnaclark | Cleartext-Password | := | YQReVH9men |
|
||||
| 27800 | jamesmooney | Cleartext-Password | := | QNUqD2tSzq |
|
||||
| 27793 | branchrvpark | Cleartext-Password | := | XfKxVZIKmm |
|
||||
| 27783 | tamythomas | Cleartext-Password | := | TT4699520858tt |
|
||||
| 27781 | pambanschbach | Cleartext-Password | := | Q2p68#*9vwF2 |
|
||||
| 27780 | josephcruz | Cleartext-Password | := | Z06oxJXrNd |
|
||||
| 29601 | kimberlyrichards2 | ClearText-Password | := | K84f7r10GT108 |
|
||||
| 27761 | franceskirby | Cleartext-Password | := | FK8179391152fk |
|
||||
| 27759 | chadwhitsell | Cleartext-Password | := | 79374B75phGy |
|
||||
| 27754 | ruthfengler | Cleartext-Password | := | 8q8MX6NQP3b6 |
|
||||
| 27755 | gordonhamilton | Cleartext-Password | := | c3495Rpuq5Sh |
|
||||
| 27751 | bobbyfisher | Cleartext-Password | := | salvagejuggle |
|
||||
| 27748 | eddieyarbrough | Cleartext-Password | := | 89298ChZWzMy |
|
||||
| 27744 | chrissyeagle | Cleartext-Password | := | 9vkX97426Sgt |
|
||||
| 27739 | victoriaobier | Cleartext-Password | := | M57B288P9 |
|
||||
| 27736 | bernardheer | Cleartext-Password | := | BH33682019BER |
|
||||
| 27734 | garycable | Cleartext-Password | := | M2w6z5Y73 |
|
||||
| 27735 | coyungemach | Cleartext-Password | := | MhS569N84e7a |
|
||||
| 27733 | michaelmccauley | Cleartext-Password | := | CPORADIO98 |
|
||||
| 27731 | lessruble | Cleartext-Password | := | 9U35SXxM2H8y |
|
||||
| 27730 | marknunnelee | Cleartext-Password | := | 833j2Ymm4yfV |
|
||||
| 27729 | elizabethchristian | Cleartext-Password | := | Webg22nj |
|
||||
| 27724 | mikebell | Cleartext-Password | := | BHF538HSEBDLY4 |
|
||||
| 27713 | krystabates | Cleartext-Password | := | KB2145445824kb |
|
||||
| 27709 | sensibleheatsystems | Cleartext-Password | := | SHQWERY23 |
|
||||
| 27708 | chrisfrancis | Cleartext-Password | := | DR45QC74M |
|
||||
| 27704 | lambandlion | Cleartext-Password | := | LL9727363567ll |
|
||||
| 27701 | markfisher | Cleartext-Password | := | 32fd8P&rw8s7 |
|
||||
| 27696 | kirkvanmeter | Cleartext-Password | := | J2sR9g^83M33 |
|
||||
| 27694 | dananance | Cleartext-Password | := | 23SP$e!ug232 |
|
||||
| 27690 | keithcrank | Cleartext-Password | := | 2zt3T5w72T3A |
|
||||
| 27687 | scottarmstrong | Cleartext-Password | := | 2SV58M55 |
|
||||
| 27683 | floydday | Cleartext-Password | := | Tfdd3254tfD |
|
||||
| 27680 | mariacortes | Cleartext-Password | := | MC2145858276mc |
|
||||
| 27668 | christianlummus | ClearText-Password | := | K6dbr631ddL |
|
||||
| 27666 | marklindsey | Cleartext-Password | := | ML9727346434ml |
|
||||
| 27658 | joeywhitfield | Cleartext-Password | := | BV758qXne446 |
|
||||
| 27654 | taekim | Cleartext-Password | := | SAN11837TCK |
|
||||
| 27652 | teresarobinson | Cleartext-Password | := | T645trdf87fR |
|
||||
| 27651 | nathanmctee | Cleartext-Password | := | N32462uu8rM |
|
||||
| 27646 | rebekahmoore | Cleartext-Password | := | R756346tfg4M |
|
||||
| 27643 | monicatrevino | Cleartext-Password | := | MT2145877143mt |
|
||||
| 27640 | rachelfuller | Cleartext-Password | := | R8364hbst |
|
||||
| 27639 | choonpang | Cleartext-Password | := | CP2143855677cp |
|
||||
| 27638 | shannonbrown | Cleartext-Password | := | S9725298223b |
|
||||
| 27637 | allentaylor | Cleartext-Password | := | A6346gge8T1 |
|
||||
| 27632 | kristenaustin | Cleartext-Password | := | KA8017916972ka |
|
||||
| 27630 | colinhopper | Cleartext-Password | := | TYVU65445IUB |
|
||||
| 27625 | mattbud | Cleartext-Password | := | kjklfda79sd |
|
||||
| 27621 | richardhill | Cleartext-Password | := | RH9729788124rh |
|
||||
| 27619 | srireddy | Cleartext-Password | := | ycHAvetmF0 |
|
||||
| 27618 | tammieventris | Cleartext-Password | := | DR45QC74M |
|
||||
| 27615 | almaacosta | Cleartext-Password | := | ENKC5DGV |
|
||||
| 27614 | chrispassonno | Cleartext-Password | := | C8766thf96P |
|
||||
| 27613 | seanbaxter | Cleartext-Password | := | SB4696679337sb |
|
||||
| 27612 | collinhartman | Cleartext-Password | := | B886tg98jt9L |
|
||||
| 27610 | michaelhughes | Cleartext-Password | := | 1RKk32MyTK |
|
||||
| 27608 | michaeltalbot | Cleartext-Password | := | Mjj1276rt99T |
|
||||
| 27606 | anagonzalez | Cleartext-Password | := | WNAHDMwWoE |
|
||||
| 27604 | leonardlewis | Cleartext-Password | := | L1877ef32L |
|
||||
| 27598 | jerryjohnson | Cleartext-Password | := | J177895aa98J |
|
||||
| 27594 | pamtoler | Cleartext-Password | := | NfxcgYQUbj |
|
||||
| 27589 | jodymccluskey | Cleartext-Password | := | JM4696883349jm |
|
||||
| 27579 | donnance | Cleartext-Password | := | 9727346814 |
|
||||
| 27577 | chrisvannatta | Cleartext-Password | := | !4694502484! |
|
||||
| 27575 | mariomerlo | Cleartext-Password | := | !2149579585! |
|
||||
| 27572 | williamarmstrong | Cleartext-Password | := | !2145510334! |
|
||||
| 27571 | trecedaschmid | Cleartext-Password | := | !4692075942! |
|
||||
| 27570 | ronlewis | Cleartext-Password | := | JDkf1AL942 |
|
||||
| 27567 | sherryerichardson | Cleartext-Password | := | DR6528BCD3S2 |
|
||||
| 27566 | joannarodriguez | Cleartext-Password | := | 394X3YR9 |
|
||||
| 27561 | dannycampbell | Cleartext-Password | := | !9726589541! |
|
||||
| 27560 | howardcomstock | Cleartext-Password | := | !3365494230! |
|
||||
| 27555 | terrymiesen | Cleartext-Password | := | !4697420828! |
|
||||
| 27550 | michaelray | Cleartext-Password | := | primitivedefinitionstoredinner |
|
||||
| 27545 | terrybates | Cleartext-Password | := | !2145786644! |
|
||||
| 27538 | gregmcintire | Cleartext-Password | := | v9368$E9mx9m |
|
||||
| 27543 | beverlyerwin | Cleartext-Password | := | MOOLAH |
|
||||
| 27518 | helenlumpkin | Cleartext-Password | := | Heehhejd0N |
|
||||
| 27508 | stevechristiaens | Cleartext-Password | := | zY272m258*vJ |
|
||||
| 27505 | judydevine | Cleartext-Password | := | OD4697669725od |
|
||||
| 27501 | jonnytaylor | Cleartext-Password | := | Zb6677&4!yky |
|
||||
| 27500 | rhondabolton | Cleartext-Password | := | RB2145786030rb |
|
||||
| 27492 | rickbeckham | Cleartext-Password | := | tVj7ZI5QA0 |
|
||||
| 27489 | jenniferreed | Cleartext-Password | := | 683P7V7R |
|
||||
| 27490 | vancepeltonen | Cleartext-Password | := | V66rdf43aaP |
|
||||
| 27486 | jacobwilliams | Cleartext-Password | := | jnlka9994jkfldsa |
|
||||
| 27482 | irvinbarojas | Cleartext-Password | := | yDeEJzYY08 |
|
||||
| 27478 | classicshear | Cleartext-Password | := | KARENALDERSON |
|
||||
| 27477 | davekiowski | Cleartext-Password | := | FNW63KXSAPT7 |
|
||||
| 27463 | dennispereyra | Cleartext-Password | := | 82s62kd9XHhd |
|
||||
| 27458 | paulsammataro | Cleartext-Password | := | P2n74V7P8g4S |
|
||||
| 27460 | janetkern | Cleartext-Password | := | j42252^Bhf44 |
|
||||
| 27457 | carlossalaises | Cleartext-Password | := | 28E358y$JFB9 |
|
||||
| 27453 | obedsandoval | Cleartext-Password | := | *H78z9xy84C& |
|
||||
| 27455 | dianewiley | Cleartext-Password | := | Diane03t4&adTL |
|
||||
| 27444 | tammylove | Cleartext-Password | := | f65NS4Ct6$29 |
|
||||
| 27441 | samanthasmith | Cleartext-Password | := | 22jmR9X#93j5 |
|
||||
| 27438 | floydallen | Cleartext-Password | := | V3864VB2 |
|
||||
| 27436 | clayrobertson2 | Cleartext-Password | := | C2147288546R |
|
||||
| 27432 | hortenciaalvarez | Cleartext-Password | := | WHTABORG3593JKS |
|
||||
| 27424 | timbagert | Cleartext-Password | := | CF18n42cY7 |
|
||||
| 27425 | davidbaker | Cleartext-Password | := | DB764g1d87rtB |
|
||||
| 27421 | janicealexander | Cleartext-Password | := | AG57TSH89L9 |
|
||||
| 27423 | timgilbert | Cleartext-Password | := | 73xi0r600Sz% |
|
||||
| 27417 | donniecampbell | Cleartext-Password | := | 6a2671bc0c1 |
|
||||
| 27418 | alanwyatt | Cleartext-Password | := | i1412r53MYr |
|
||||
| 27413 | jesusrios | Cleartext-Password | := | 8Di6QMs7%7m1 |
|
||||
| 27408 | penneywarner | Cleartext-Password | := | b4h53N6c#5wo |
|
||||
| 27409 | veronabaptist | Cleartext-Password | := | DAY753LIGHT253 |
|
||||
| 27406 | whiteywhite | Cleartext-Password | := | 45z6r*H4418n |
|
||||
| 27404 | grahammcintire | Cleartext-Password | := | U5Y3hA3g*14L |
|
||||
| 27402 | louislafon | Cleartext-Password | := | RFTRE4825CVKL |
|
||||
| 27397 | ausencioluna | Cleartext-Password | := | ABN765MNL |
|
||||
| 27374 | davidvillanueva | Cleartext-Password | := | DV5489CRPMWBQ |
|
||||
| 29620 | sayedahaque | ClearText-Password | := | YR4Sytbu |
|
||||
| 29621 | coryrees | ClearText-Password | := | yt5c6ujhvu |
|
||||
| 29622 | brianamartinez | ClearText-Password | := | ktydr6428 |
|
||||
| 29623 | khushbooagarwal | ClearText-Password | := | UUTFVUCTC446 |
|
||||
| 29624 | elisasanders | ClearText-Password | := | OYTCu3276 |
|
||||
| 29625 | josemedrano | ClearText-Password | := | UYVITRUR24 |
|
||||
| 29626 | karengreen | ClearText-Password | := | UTKCYI674 |
|
||||
| 29627 | nicholasterry | ClearText-Password | := | VUTYVL746 |
|
||||
| 29628 | leslieperalta | ClearText-Password | := | RYC66747 |
|
||||
| 29629 | khushbooagarwal2 | ClearText-Password | := | iytf65gkj |
|
||||
| 29630 | sriahobilamuth | ClearText-Password | := | RTCESW24 |
|
||||
| 29631 | royrogers | ClearText-Password | := | TYDGVBNC |
|
||||
| 29632 | arturoprieto | ClearText-Password | := | 1653APVN877 |
|
||||
| 29633 | ericamorris | ClearText-Password | := | E16488VN387 |
|
||||
| 29617 | belindamillener | ClearText-Password | := | Uiyu7280 |
|
||||
| 29618 | kailynnbarnfield | ClearText-Password | := | HAkuguuvoy1 |
|
||||
| 29619 | thomasgraham | ClearText-Password | := | YUiygiiu4 |
|
||||
| 27315 | debravega | Cleartext-Password | := | RCG8618BDUMSR |
|
||||
| 29582 | davidlanman | Cleartext-Password | := | 2BMMRYQ2PHEA |
|
||||
| 29583 | anthonylongo | Cleartext-Password | := | 9MLG8HVME4J3 |
|
||||
| 29584 | konradwoelffer | Cleartext-Password | := | BCQ8NRFVNA3R |
|
||||
| 29585 | marthaflores | Cleartext-Password | := | KG2QEG36348V |
|
||||
| 29586 | connorspicer | Cleartext-Password | := | 6U2BWJKGCX8G |
|
||||
| 29588 | korybiggsshop | Cleartext-Password | := | JA4SXBGKHFUL |
|
||||
| 29589 | ednagriffin | Cleartext-Password | := | AXA8EZEAN7DJ |
|
||||
| 29590 | richardrosson | Cleartext-Password | := | 9J5L6MEH4Y7Y |
|
||||
| 29603 | allentaylor2 | ClearText-Password | := | NCJW87FW8723 |
|
||||
| 29604 | alextovias | ClearText-Password | := | 7VSgrVO1WX |
|
||||
| 29605 | mikecurrence | ClearText-Password | := | MKH23FG79C |
|
||||
| 29594 | terryrector | Cleartext-Password | := | QUPP83ZUUSGL |
|
||||
| 29595 | donnacampbell | Cleartext-Password | := | KYCNTWS3929N |
|
||||
| 29600 | billmctee | ClearText-Password | := | Bdge6388M |
|
||||
41
gaiia/src/gaiia/__init__.py
Normal file
41
gaiia/src/gaiia/__init__.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
"""gaiia GraphQL API client.
|
||||
|
||||
Quick start:
|
||||
|
||||
from gaiia import GaiiaClient
|
||||
|
||||
with GaiiaClient(api_key="gaiia_sk_live_...") as g:
|
||||
result = g.query("{ technicians(first: 10) { nodes { id firstName lastName } } }")
|
||||
"""
|
||||
|
||||
from gaiia.client import AsyncGaiiaClient, GaiiaClient
|
||||
from gaiia.errors import (
|
||||
GaiiaAPIError,
|
||||
GaiiaError,
|
||||
GaiiaMutationError,
|
||||
GaiiaRateLimitedError,
|
||||
GaiiaTransportError,
|
||||
)
|
||||
from gaiia.globalid import decode_global_id, encode_global_id
|
||||
from gaiia.ratelimit import RateLimitInfo
|
||||
from gaiia.webhooks import (
|
||||
WebhookSignatureError,
|
||||
verify_webhook_signature,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AsyncGaiiaClient",
|
||||
"GaiiaAPIError",
|
||||
"GaiiaClient",
|
||||
"GaiiaError",
|
||||
"GaiiaMutationError",
|
||||
"GaiiaRateLimitedError",
|
||||
"GaiiaTransportError",
|
||||
"RateLimitInfo",
|
||||
"WebhookSignatureError",
|
||||
"decode_global_id",
|
||||
"encode_global_id",
|
||||
"verify_webhook_signature",
|
||||
]
|
||||
|
||||
__version__ = "0.1.0"
|
||||
392
gaiia/src/gaiia/client.py
Normal file
392
gaiia/src/gaiia/client.py
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
"""Sync and async GraphQL clients for the gaiia API."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import time
|
||||
from types import TracebackType
|
||||
from typing import Any, AsyncIterator, Iterator
|
||||
|
||||
import httpx
|
||||
|
||||
from gaiia.errors import (
|
||||
GaiiaAPIError,
|
||||
GaiiaMutationError,
|
||||
GaiiaRateLimitedError,
|
||||
GaiiaTransportError,
|
||||
GraphQLError,
|
||||
)
|
||||
from gaiia.pagination import aiter_nodes, iter_nodes
|
||||
from gaiia.ratelimit import RateLimitInfo
|
||||
|
||||
DEFAULT_BASE_URL = "https://api.gaiia.com/api/v1"
|
||||
DEFAULT_TIMEOUT = 30.0
|
||||
API_KEY_HEADER = "X-Gaiia-Api-Key"
|
||||
TIMEZONE_HEADER = "x-timezone"
|
||||
USER_AGENT = "gaiia-py/0.1.0"
|
||||
|
||||
|
||||
def _build_headers(
|
||||
api_key: str, timezone: str | None, extra: dict[str, str] | None
|
||||
) -> dict[str, str]:
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"User-Agent": USER_AGENT,
|
||||
API_KEY_HEADER: api_key,
|
||||
}
|
||||
if timezone:
|
||||
headers[TIMEZONE_HEADER] = timezone
|
||||
if extra:
|
||||
headers.update(extra)
|
||||
return headers
|
||||
|
||||
|
||||
def _classify_errors(raw_errors: list[dict[str, Any]]) -> tuple[bool, list[GraphQLError]]:
|
||||
"""Return ``(rate_limited, parsed_errors)`` for top-level GraphQL errors."""
|
||||
errors = [GraphQLError.from_dict(e) for e in raw_errors]
|
||||
rate_limited = any(e.code == "RATE_LIMITED" for e in errors)
|
||||
return rate_limited, errors
|
||||
|
||||
|
||||
def _raise_for_payload(payload: dict[str, Any]) -> None:
|
||||
raw_errors = payload.get("errors")
|
||||
if not raw_errors:
|
||||
return
|
||||
rate_limited, errors = _classify_errors(raw_errors)
|
||||
if rate_limited:
|
||||
ext = errors[0].extensions
|
||||
retry_at = None
|
||||
if ext.get("retryAt"):
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
retry_at = datetime.fromisoformat(str(ext["retryAt"]).replace("Z", "+00:00"))
|
||||
except ValueError:
|
||||
retry_at = None
|
||||
raise GaiiaRateLimitedError(
|
||||
errors,
|
||||
cost=ext.get("cost"),
|
||||
limit=ext.get("limit"),
|
||||
used=ext.get("used"),
|
||||
remaining=ext.get("remaining"),
|
||||
retry_at=retry_at,
|
||||
)
|
||||
raise GaiiaAPIError(errors, data=payload.get("data"))
|
||||
|
||||
|
||||
class _Base:
|
||||
def __init__(
|
||||
self,
|
||||
api_key: str | None = None,
|
||||
*,
|
||||
base_url: str = DEFAULT_BASE_URL,
|
||||
timezone: str | None = None,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
default_headers: dict[str, str] | None = None,
|
||||
max_retries: int = 0,
|
||||
) -> None:
|
||||
resolved = api_key if api_key is not None else os.environ.get("GAIIA_KEY")
|
||||
if not resolved:
|
||||
raise ValueError(
|
||||
"api_key is required (pass api_key= or set the GAIIA_KEY env var)"
|
||||
)
|
||||
self._api_key = resolved
|
||||
self._base_url = base_url
|
||||
self._timezone = timezone
|
||||
self._timeout = timeout
|
||||
self._default_headers = default_headers
|
||||
self._max_retries = max_retries
|
||||
self.last_rate_limit: RateLimitInfo | None = None
|
||||
|
||||
def _headers(self, extra: dict[str, str] | None = None) -> dict[str, str]:
|
||||
merged = dict(self._default_headers or {})
|
||||
if extra:
|
||||
merged.update(extra)
|
||||
return _build_headers(self._api_key, self._timezone, merged)
|
||||
|
||||
|
||||
class GaiiaClient(_Base):
|
||||
"""Synchronous gaiia GraphQL client."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api_key: str | None = None,
|
||||
*,
|
||||
base_url: str = DEFAULT_BASE_URL,
|
||||
timezone: str | None = None,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
default_headers: dict[str, str] | None = None,
|
||||
max_retries: int = 0,
|
||||
transport: httpx.BaseTransport | None = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
api_key,
|
||||
base_url=base_url,
|
||||
timezone=timezone,
|
||||
timeout=timeout,
|
||||
default_headers=default_headers,
|
||||
max_retries=max_retries,
|
||||
)
|
||||
self._http = httpx.Client(timeout=timeout, transport=transport)
|
||||
|
||||
def __enter__(self) -> GaiiaClient:
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: type[BaseException] | None,
|
||||
exc: BaseException | None,
|
||||
tb: TracebackType | None,
|
||||
) -> None:
|
||||
self.close()
|
||||
|
||||
def close(self) -> None:
|
||||
self._http.close()
|
||||
|
||||
def query(
|
||||
self,
|
||||
query: str,
|
||||
variables: dict[str, Any] | None = None,
|
||||
*,
|
||||
operation_name: str | None = None,
|
||||
timezone: str | None = None,
|
||||
extra_headers: dict[str, str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Run a GraphQL query/mutation and return the ``data`` payload.
|
||||
|
||||
Raises :class:`GaiiaAPIError` on top-level errors,
|
||||
:class:`GaiiaRateLimitedError` on RATE_LIMITED, and
|
||||
:class:`GaiiaTransportError` on network failures.
|
||||
"""
|
||||
body: dict[str, Any] = {"query": query}
|
||||
if variables is not None:
|
||||
body["variables"] = variables
|
||||
if operation_name is not None:
|
||||
body["operationName"] = operation_name
|
||||
|
||||
per_call_headers = dict(extra_headers or {})
|
||||
if timezone is not None:
|
||||
per_call_headers[TIMEZONE_HEADER] = timezone
|
||||
headers = self._headers(per_call_headers)
|
||||
|
||||
attempt = 0
|
||||
while True:
|
||||
attempt += 1
|
||||
try:
|
||||
resp = self._http.post(self._base_url, json=body, headers=headers)
|
||||
except httpx.HTTPError as e:
|
||||
raise GaiiaTransportError(str(e)) from e
|
||||
|
||||
self.last_rate_limit = RateLimitInfo.from_headers(resp.headers)
|
||||
try:
|
||||
payload = resp.json()
|
||||
except ValueError as e:
|
||||
raise GaiiaTransportError(
|
||||
f"non-JSON response from gaiia (HTTP {resp.status_code})"
|
||||
) from e
|
||||
|
||||
try:
|
||||
_raise_for_payload(payload)
|
||||
except GaiiaRateLimitedError as e:
|
||||
if attempt > self._max_retries:
|
||||
raise
|
||||
_sleep_until(e.retry_at)
|
||||
continue
|
||||
|
||||
if resp.status_code >= 500:
|
||||
raise GaiiaTransportError(
|
||||
f"gaiia returned HTTP {resp.status_code}: {resp.text[:200]}"
|
||||
)
|
||||
return payload.get("data") or {}
|
||||
|
||||
def mutate(
|
||||
self,
|
||||
query: str,
|
||||
mutation_name: str,
|
||||
variables: dict[str, Any] | None = None,
|
||||
*,
|
||||
timezone: str | None = None,
|
||||
raise_on_payload_errors: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
"""Run a mutation and inspect its ``errors`` payload field.
|
||||
|
||||
Returns the mutation's result object (e.g. the contents of
|
||||
``data.createTicket``). If ``raise_on_payload_errors`` is true and the
|
||||
result contains a non-empty ``errors`` list, :class:`GaiiaMutationError`
|
||||
is raised.
|
||||
"""
|
||||
data = self.query(query, variables, timezone=timezone)
|
||||
result = data.get(mutation_name)
|
||||
if result is None:
|
||||
raise GaiiaAPIError(
|
||||
[GraphQLError(message=f"mutation {mutation_name!r} not in response", code=None)],
|
||||
data=data,
|
||||
)
|
||||
errors = result.get("errors") or []
|
||||
if errors and raise_on_payload_errors:
|
||||
raise GaiiaMutationError(mutation_name, errors, payload=result)
|
||||
return result
|
||||
|
||||
def iter_nodes(
|
||||
self,
|
||||
query: str,
|
||||
connection_path: str,
|
||||
variables: dict[str, Any] | None = None,
|
||||
*,
|
||||
cursor_var: str = "after",
|
||||
timezone: str | None = None,
|
||||
) -> Iterator[Any]:
|
||||
"""Iterate every node across all pages of a Connection.
|
||||
|
||||
``query`` must accept the cursor variable (default ``$after``) and use
|
||||
it as the ``after:`` argument on the paginated field.
|
||||
"""
|
||||
base_vars = dict(variables or {})
|
||||
|
||||
def fetch_page(cursor: str | None) -> dict[str, Any]:
|
||||
v = dict(base_vars)
|
||||
v[cursor_var] = cursor
|
||||
return self.query(query, v, timezone=timezone)
|
||||
|
||||
yield from iter_nodes(fetch_page, connection_path)
|
||||
|
||||
|
||||
class AsyncGaiiaClient(_Base):
|
||||
"""Asynchronous gaiia GraphQL client."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api_key: str | None = None,
|
||||
*,
|
||||
base_url: str = DEFAULT_BASE_URL,
|
||||
timezone: str | None = None,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
default_headers: dict[str, str] | None = None,
|
||||
max_retries: int = 0,
|
||||
transport: httpx.AsyncBaseTransport | None = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
api_key,
|
||||
base_url=base_url,
|
||||
timezone=timezone,
|
||||
timeout=timeout,
|
||||
default_headers=default_headers,
|
||||
max_retries=max_retries,
|
||||
)
|
||||
self._http = httpx.AsyncClient(timeout=timeout, transport=transport)
|
||||
|
||||
async def __aenter__(self) -> AsyncGaiiaClient:
|
||||
return self
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: type[BaseException] | None,
|
||||
exc: BaseException | None,
|
||||
tb: TracebackType | None,
|
||||
) -> None:
|
||||
await self.aclose()
|
||||
|
||||
async def aclose(self) -> None:
|
||||
await self._http.aclose()
|
||||
|
||||
async def query(
|
||||
self,
|
||||
query: str,
|
||||
variables: dict[str, Any] | None = None,
|
||||
*,
|
||||
operation_name: str | None = None,
|
||||
timezone: str | None = None,
|
||||
extra_headers: dict[str, str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
body: dict[str, Any] = {"query": query}
|
||||
if variables is not None:
|
||||
body["variables"] = variables
|
||||
if operation_name is not None:
|
||||
body["operationName"] = operation_name
|
||||
|
||||
per_call_headers = dict(extra_headers or {})
|
||||
if timezone is not None:
|
||||
per_call_headers[TIMEZONE_HEADER] = timezone
|
||||
headers = self._headers(per_call_headers)
|
||||
|
||||
attempt = 0
|
||||
while True:
|
||||
attempt += 1
|
||||
try:
|
||||
resp = await self._http.post(self._base_url, json=body, headers=headers)
|
||||
except httpx.HTTPError as e:
|
||||
raise GaiiaTransportError(str(e)) from e
|
||||
|
||||
self.last_rate_limit = RateLimitInfo.from_headers(resp.headers)
|
||||
try:
|
||||
payload = resp.json()
|
||||
except ValueError as e:
|
||||
raise GaiiaTransportError(
|
||||
f"non-JSON response from gaiia (HTTP {resp.status_code})"
|
||||
) from e
|
||||
|
||||
try:
|
||||
_raise_for_payload(payload)
|
||||
except GaiiaRateLimitedError as e:
|
||||
if attempt > self._max_retries:
|
||||
raise
|
||||
_sleep_until(e.retry_at)
|
||||
continue
|
||||
|
||||
if resp.status_code >= 500:
|
||||
raise GaiiaTransportError(
|
||||
f"gaiia returned HTTP {resp.status_code}: {resp.text[:200]}"
|
||||
)
|
||||
return payload.get("data") or {}
|
||||
|
||||
async def mutate(
|
||||
self,
|
||||
query: str,
|
||||
mutation_name: str,
|
||||
variables: dict[str, Any] | None = None,
|
||||
*,
|
||||
timezone: str | None = None,
|
||||
raise_on_payload_errors: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
data = await self.query(query, variables, timezone=timezone)
|
||||
result = data.get(mutation_name)
|
||||
if result is None:
|
||||
raise GaiiaAPIError(
|
||||
[GraphQLError(message=f"mutation {mutation_name!r} not in response", code=None)],
|
||||
data=data,
|
||||
)
|
||||
errors = result.get("errors") or []
|
||||
if errors and raise_on_payload_errors:
|
||||
raise GaiiaMutationError(mutation_name, errors, payload=result)
|
||||
return result
|
||||
|
||||
async def iter_nodes(
|
||||
self,
|
||||
query: str,
|
||||
connection_path: str,
|
||||
variables: dict[str, Any] | None = None,
|
||||
*,
|
||||
cursor_var: str = "after",
|
||||
timezone: str | None = None,
|
||||
) -> AsyncIterator[Any]:
|
||||
base_vars = dict(variables or {})
|
||||
|
||||
async def fetch_page(cursor: str | None) -> dict[str, Any]:
|
||||
v = dict(base_vars)
|
||||
v[cursor_var] = cursor
|
||||
return await self.query(query, v, timezone=timezone)
|
||||
|
||||
async for node in aiter_nodes(fetch_page, connection_path):
|
||||
yield node
|
||||
|
||||
|
||||
def _sleep_until(retry_at: Any) -> None:
|
||||
if not retry_at:
|
||||
time.sleep(1.0)
|
||||
return
|
||||
delta = retry_at.timestamp() - time.time()
|
||||
if delta > 0:
|
||||
time.sleep(min(delta, 60.0))
|
||||
else:
|
||||
time.sleep(1.0)
|
||||
91
gaiia/src/gaiia/errors.py
Normal file
91
gaiia/src/gaiia/errors.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
"""Exception types raised by the gaiia client."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
class GaiiaError(Exception):
|
||||
"""Base class for all gaiia client errors."""
|
||||
|
||||
|
||||
class GaiiaTransportError(GaiiaError):
|
||||
"""Network/transport failure talking to the gaiia API."""
|
||||
|
||||
|
||||
@dataclass
|
||||
class GraphQLError:
|
||||
message: str
|
||||
code: str | None = None
|
||||
path: list[str | int] | None = None
|
||||
extensions: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, raw: dict[str, Any]) -> GraphQLError:
|
||||
extensions = dict(raw.get("extensions") or {})
|
||||
return cls(
|
||||
message=raw.get("message", ""),
|
||||
code=extensions.get("code"),
|
||||
path=raw.get("path"),
|
||||
extensions=extensions,
|
||||
)
|
||||
|
||||
|
||||
class GaiiaAPIError(GaiiaError):
|
||||
"""One or more top-level GraphQL errors were returned."""
|
||||
|
||||
def __init__(self, errors: list[GraphQLError], data: Any | None = None) -> None:
|
||||
self.errors = errors
|
||||
self.data = data
|
||||
msg = "; ".join(e.message for e in errors) or "gaiia API error"
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
class GaiiaMutationError(GaiiaError):
|
||||
"""A mutation returned validation/expected errors under data.<mutation>.errors.
|
||||
|
||||
These are the GraphQL "200 OK with errors in the payload" responses that
|
||||
represent expected failure modes (validation, business rules) rather than
|
||||
transport or schema issues.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
mutation: str,
|
||||
errors: list[dict[str, Any]],
|
||||
payload: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
self.mutation = mutation
|
||||
self.errors = errors
|
||||
self.payload = payload
|
||||
codes = [e.get("code") for e in errors if e.get("code")]
|
||||
msg = (
|
||||
f"mutation {mutation!r} returned errors: "
|
||||
+ ", ".join(f"{c}: {e.get('message','')}" for c, e in zip(codes, errors, strict=False))
|
||||
if codes
|
||||
else f"mutation {mutation!r} returned errors"
|
||||
)
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
class GaiiaRateLimitedError(GaiiaAPIError):
|
||||
"""Raised when the API returns a RATE_LIMITED error."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
errors: list[GraphQLError],
|
||||
*,
|
||||
cost: int | None = None,
|
||||
limit: int | None = None,
|
||||
used: int | None = None,
|
||||
remaining: int | None = None,
|
||||
retry_at: datetime | None = None,
|
||||
) -> None:
|
||||
super().__init__(errors)
|
||||
self.cost = cost
|
||||
self.limit = limit
|
||||
self.used = used
|
||||
self.remaining = remaining
|
||||
self.retry_at = retry_at
|
||||
65
gaiia/src/gaiia/globalid.py
Normal file
65
gaiia/src/gaiia/globalid.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
"""Encode and decode gaiia GlobalIDs.
|
||||
|
||||
A GlobalID looks like ``account_pwE84wz4Mw15LPX5YE8Z3o``: a snake-cased entity
|
||||
type, an underscore, and a 22-char Flickr Base-58 encoding of the underlying
|
||||
128-bit UUID. This matches the ``short-uuid`` library that gaiia uses on the
|
||||
server side.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from uuid import UUID
|
||||
|
||||
_ALPHABET = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
||||
_BASE = len(_ALPHABET)
|
||||
_TARGET_LEN = 22
|
||||
_TYPE_RE = re.compile(r"(?<!^)(?=[A-Z])")
|
||||
|
||||
|
||||
def _snake_case(name: str) -> str:
|
||||
return _TYPE_RE.sub("_", name).lower()
|
||||
|
||||
|
||||
def encode_global_id(type_name: str, uuid_str: str | UUID) -> str:
|
||||
"""Build a GlobalID from a type name (e.g. ``Account``) and a UUID."""
|
||||
if isinstance(uuid_str, UUID):
|
||||
stripped = uuid_str.hex
|
||||
else:
|
||||
stripped = str(uuid_str).replace("-", "").lower()
|
||||
if len(stripped) != 32 or any(c not in "0123456789abcdef" for c in stripped):
|
||||
raise ValueError(f"not a valid uuid: {uuid_str!r}")
|
||||
|
||||
num = int(stripped, 16)
|
||||
chars: list[str] = []
|
||||
if num == 0:
|
||||
chars.append(_ALPHABET[0])
|
||||
else:
|
||||
while num > 0:
|
||||
num, rem = divmod(num, _BASE)
|
||||
chars.append(_ALPHABET[rem])
|
||||
chars.reverse()
|
||||
short = "".join(chars).rjust(_TARGET_LEN, _ALPHABET[0])
|
||||
return f"{_snake_case(type_name)}_{short}"
|
||||
|
||||
|
||||
def decode_global_id(global_id: str) -> tuple[str, str]:
|
||||
"""Split a GlobalID into ``(type_snake_case, uuid_str)``."""
|
||||
if "_" not in global_id:
|
||||
raise ValueError(f"not a global id: {global_id!r}")
|
||||
type_part, _, short_id = global_id.rpartition("_")
|
||||
if not type_part or not short_id:
|
||||
raise ValueError(f"malformed global id: {global_id!r}")
|
||||
num = 0
|
||||
for ch in short_id:
|
||||
idx = _ALPHABET.find(ch)
|
||||
if idx < 0:
|
||||
raise ValueError(f"invalid base58 char {ch!r} in {global_id!r}")
|
||||
num = num * _BASE + idx
|
||||
hex_str = format(num, "x").rjust(32, "0")
|
||||
if len(hex_str) > 32:
|
||||
raise ValueError(f"global id decodes to oversized uuid: {global_id!r}")
|
||||
uuid_str = (
|
||||
f"{hex_str[0:8]}-{hex_str[8:12]}-{hex_str[12:16]}-{hex_str[16:20]}-{hex_str[20:32]}"
|
||||
)
|
||||
return type_part, uuid_str
|
||||
61
gaiia/src/gaiia/pagination.py
Normal file
61
gaiia/src/gaiia/pagination.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""Helpers for cursor-based pagination over gaiia Connection types."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, AsyncIterator, Iterator
|
||||
|
||||
|
||||
def extract_connection(data: dict[str, Any], path: str) -> dict[str, Any]:
|
||||
"""Walk a dotted path into a GraphQL ``data`` payload and return the Connection node."""
|
||||
node: Any = data
|
||||
for part in path.split("."):
|
||||
if not isinstance(node, dict):
|
||||
raise KeyError(f"path {path!r} not found in response")
|
||||
node = node.get(part)
|
||||
if node is None:
|
||||
raise KeyError(f"path {path!r} not found in response (broke at {part!r})")
|
||||
if not isinstance(node, dict) or "pageInfo" not in node:
|
||||
raise ValueError(f"path {path!r} did not point to a Connection (no pageInfo)")
|
||||
return node
|
||||
|
||||
|
||||
def iter_nodes(
|
||||
fetch_page: "Callable[[str | None], dict[str, Any]]", # noqa: F821
|
||||
connection_path: str,
|
||||
) -> Iterator[Any]:
|
||||
"""Yield nodes one by one across all pages of a Connection.
|
||||
|
||||
``fetch_page`` takes the current ``after`` cursor (``None`` on the first
|
||||
page) and returns the full GraphQL ``data`` payload for that page.
|
||||
"""
|
||||
cursor: str | None = None
|
||||
while True:
|
||||
data = fetch_page(cursor)
|
||||
conn = extract_connection(data, connection_path)
|
||||
for node in conn.get("nodes") or []:
|
||||
yield node
|
||||
page_info = conn.get("pageInfo") or {}
|
||||
if not page_info.get("hasNextPage"):
|
||||
return
|
||||
cursor = page_info.get("endCursor")
|
||||
if not cursor:
|
||||
return
|
||||
|
||||
|
||||
async def aiter_nodes(
|
||||
fetch_page: "Callable[[str | None], Awaitable[dict[str, Any]]]", # noqa: F821
|
||||
connection_path: str,
|
||||
) -> AsyncIterator[Any]:
|
||||
"""Async version of :func:`iter_nodes`."""
|
||||
cursor: str | None = None
|
||||
while True:
|
||||
data = await fetch_page(cursor)
|
||||
conn = extract_connection(data, connection_path)
|
||||
for node in conn.get("nodes") or []:
|
||||
yield node
|
||||
page_info = conn.get("pageInfo") or {}
|
||||
if not page_info.get("hasNextPage"):
|
||||
return
|
||||
cursor = page_info.get("endCursor")
|
||||
if not cursor:
|
||||
return
|
||||
0
gaiia/src/gaiia/py.typed
Normal file
0
gaiia/src/gaiia/py.typed
Normal file
56
gaiia/src/gaiia/ratelimit.py
Normal file
56
gaiia/src/gaiia/ratelimit.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""Parse gaiia rate-limit response headers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Mapping
|
||||
|
||||
|
||||
@dataclass
|
||||
class RateLimitInfo:
|
||||
allowed: bool | None
|
||||
cost: int | None
|
||||
limit: int | None
|
||||
used: int | None
|
||||
remaining: int | None
|
||||
retry_at: datetime | None
|
||||
|
||||
@classmethod
|
||||
def from_headers(cls, headers: Mapping[str, str]) -> RateLimitInfo:
|
||||
def _get(name: str) -> str | None:
|
||||
for k, v in headers.items():
|
||||
if k.lower() == name.lower():
|
||||
return v
|
||||
return None
|
||||
|
||||
def _int(name: str) -> int | None:
|
||||
v = _get(name)
|
||||
try:
|
||||
return int(v) if v is not None else None
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def _bool(name: str) -> bool | None:
|
||||
v = _get(name)
|
||||
if v is None:
|
||||
return None
|
||||
return v.strip().lower() == "true"
|
||||
|
||||
def _dt(name: str) -> datetime | None:
|
||||
v = _get(name)
|
||||
if not v:
|
||||
return None
|
||||
try:
|
||||
return datetime.fromisoformat(v.replace("Z", "+00:00"))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
return cls(
|
||||
allowed=_bool("X-Rate-Limit-Allowed"),
|
||||
cost=_int("X-Rate-Limit-Cost"),
|
||||
limit=_int("X-Rate-Limit-Limit"),
|
||||
used=_int("X-Rate-Limit-Used"),
|
||||
remaining=_int("X-Rate-Limit-Remaining"),
|
||||
retry_at=_dt("X-Rate-Limit-Retry-At") or _dt("X-Rate-Limit-Retry-at"),
|
||||
)
|
||||
93
gaiia/src/gaiia/webhooks.py
Normal file
93
gaiia/src/gaiia/webhooks.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
"""Webhook signature verification for incoming gaiia webhooks.
|
||||
|
||||
Each delivery includes the header
|
||||
``X-Gaiia-Webhook-Signature: t=<unix-ts>,v1=<hex-sha256-hmac>``. The signature
|
||||
is HMAC-SHA256 over ``"${t}.${rawBody}"`` keyed by the endpoint secret. Compare
|
||||
in constant time and reject if ``t`` is outside your tolerance window.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import time
|
||||
from typing import Iterable
|
||||
|
||||
from gaiia.errors import GaiiaError
|
||||
|
||||
SIGNATURE_HEADER = "X-Gaiia-Webhook-Signature"
|
||||
DEFAULT_TOLERANCE_SECONDS = 5 * 60
|
||||
|
||||
|
||||
class WebhookSignatureError(GaiiaError):
|
||||
"""Raised when a webhook signature fails verification."""
|
||||
|
||||
|
||||
def _parse_header(header_value: str) -> tuple[str | None, list[str]]:
|
||||
timestamp: str | None = None
|
||||
v1_signatures: list[str] = []
|
||||
for chunk in header_value.split(","):
|
||||
if "=" not in chunk:
|
||||
continue
|
||||
prefix, _, value = chunk.partition("=")
|
||||
prefix = prefix.strip()
|
||||
value = value.strip()
|
||||
if prefix == "t":
|
||||
timestamp = value
|
||||
elif prefix == "v1":
|
||||
v1_signatures.append(value)
|
||||
return timestamp, v1_signatures
|
||||
|
||||
|
||||
def _compute_signature(secret: str | bytes, timestamp: str, raw_body: str | bytes) -> str:
|
||||
if isinstance(secret, str):
|
||||
secret = secret.encode("utf-8")
|
||||
if isinstance(raw_body, bytes):
|
||||
body_text = raw_body.decode("utf-8")
|
||||
else:
|
||||
body_text = raw_body
|
||||
payload = f"{timestamp}.{body_text}".encode("utf-8")
|
||||
return hmac.new(secret, payload, hashlib.sha256).hexdigest()
|
||||
|
||||
|
||||
def verify_webhook_signature(
|
||||
*,
|
||||
header_value: str,
|
||||
raw_body: str | bytes,
|
||||
secret: str | bytes,
|
||||
tolerance_seconds: int = DEFAULT_TOLERANCE_SECONDS,
|
||||
now: float | None = None,
|
||||
) -> None:
|
||||
"""Verify a webhook delivery. Raises :class:`WebhookSignatureError` on failure.
|
||||
|
||||
``raw_body`` must be the exact bytes/string the server signed — do not
|
||||
re-serialize a parsed JSON body, since whitespace differences will break
|
||||
the HMAC.
|
||||
"""
|
||||
if not header_value:
|
||||
raise WebhookSignatureError("missing signature header")
|
||||
timestamp, candidates = _parse_header(header_value)
|
||||
if timestamp is None:
|
||||
raise WebhookSignatureError("signature header missing timestamp (t=...)")
|
||||
if not candidates:
|
||||
raise WebhookSignatureError("signature header missing v1 signatures")
|
||||
|
||||
try:
|
||||
ts_int = int(timestamp)
|
||||
except ValueError as e:
|
||||
raise WebhookSignatureError(f"signature timestamp not an integer: {timestamp!r}") from e
|
||||
|
||||
current = time.time() if now is None else now
|
||||
if abs(current - ts_int) > tolerance_seconds:
|
||||
raise WebhookSignatureError(
|
||||
f"signature timestamp outside tolerance "
|
||||
f"({tolerance_seconds}s): {abs(current - ts_int):.0f}s drift"
|
||||
)
|
||||
|
||||
expected = _compute_signature(secret, timestamp, raw_body)
|
||||
if not _any_match(expected, candidates):
|
||||
raise WebhookSignatureError("no signature matched expected HMAC")
|
||||
|
||||
|
||||
def _any_match(expected: str, candidates: Iterable[str]) -> bool:
|
||||
return any(hmac.compare_digest(expected, c) for c in candidates)
|
||||
160
gaiia/sync_all_radius_groups.py
Normal file
160
gaiia/sync_all_radius_groups.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Run 'Update RADIUS Account Groups' for every account in Gaiia.
|
||||
Status must be UPPERCASE (ACTIVE, SUSPENDED, etc.)
|
||||
|
||||
Usage:
|
||||
source .envrc
|
||||
uv run python3 sync_all_radius_groups.py --dry-run (preview)
|
||||
uv run python3 sync_all_radius_groups.py (execute)
|
||||
"""
|
||||
|
||||
from gaiia import GaiiaClient, GaiiaAPIError, GaiiaRateLimitedError
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
|
||||
WF_ID = "workflow_fLXTNCvridPqwEEXxf3CK1"
|
||||
|
||||
|
||||
def list_accounts(client):
|
||||
"""Paginate through all accounts, return [{id, name, status, productIds}]."""
|
||||
accounts = []
|
||||
after = None
|
||||
page = 0
|
||||
|
||||
while True:
|
||||
page += 1
|
||||
data = client.query("""
|
||||
query Q($after: String) {
|
||||
accounts(first: 250, after: $after) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
status { name }
|
||||
billingSubscriptions {
|
||||
nodes {
|
||||
productVersion {
|
||||
product { id name slug }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pageInfo { hasNextPage endCursor }
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
""", {"after": after} if after else {})
|
||||
|
||||
result = data['accounts']
|
||||
|
||||
for acct in result['nodes']:
|
||||
status_name = acct['status']['name'] if acct['status'] else ''
|
||||
products = []
|
||||
for sub in (acct.get('billingSubscriptions') or {}).get('nodes', []):
|
||||
pv = sub.get('productVersion') or {}
|
||||
p = pv.get('product') if pv else None
|
||||
if p and p['id'] not in products:
|
||||
products.append(p['id'])
|
||||
|
||||
accounts.append({
|
||||
'id': acct['id'],
|
||||
'name': acct.get('name', '') or '',
|
||||
'status': status_name,
|
||||
'productIds': products,
|
||||
})
|
||||
|
||||
sys.stderr.write(f"\r Page {page}: {len(accounts)} accounts so far...")
|
||||
sys.stderr.flush()
|
||||
|
||||
page_info = result['pageInfo']
|
||||
if not page_info.get('hasNextPage'):
|
||||
break
|
||||
after = page_info['endCursor']
|
||||
|
||||
sys.stderr.write("\n")
|
||||
return accounts
|
||||
|
||||
|
||||
def sync_account(client, acct, dry_run=False):
|
||||
"""Run the Update RADIUS Account Groups workflow for one account."""
|
||||
status_upper = acct['status'].upper()
|
||||
wf_input = {
|
||||
"accountId": acct['id'],
|
||||
"status": status_upper,
|
||||
"productIds": acct['productIds'],
|
||||
}
|
||||
|
||||
if dry_run:
|
||||
name = acct['name'] or '(no name)'
|
||||
print(f" [DRY-RUN] {name} status={status_upper} products={len(acct['productIds'])}")
|
||||
return True
|
||||
|
||||
try:
|
||||
result = client.query("""
|
||||
mutation Run($input: StartWorkflowExecutionInput!) {
|
||||
startWorkflowExecution(input: $input) {
|
||||
workflowExecution { id status }
|
||||
}
|
||||
}
|
||||
""", {"input": {"workflowId": WF_ID, "input": wf_input}})
|
||||
|
||||
we = result['startWorkflowExecution']['workflowExecution']
|
||||
return we is not None
|
||||
except GaiiaAPIError as e:
|
||||
print(f" FAILED {acct.get('name','?')}: API error - {e}")
|
||||
return False
|
||||
except GaiiaRateLimitedError as e:
|
||||
print(f" RATE LIMITED - sleeping until {e.retry_at}")
|
||||
if e.retry_at:
|
||||
wait = max(0, (e.retry_at.timestamp() - time.time()))
|
||||
time.sleep(wait + 1)
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
dry_run = "--dry-run" in sys.argv
|
||||
|
||||
with GaiiaClient(timezone='America/Chicago') as g:
|
||||
print("Listing all accounts...")
|
||||
accounts = list_accounts(g)
|
||||
print(f"\nFound {len(accounts)} accounts")
|
||||
|
||||
# Stats
|
||||
statuses = {}
|
||||
for a in accounts:
|
||||
s = a['status'].upper()
|
||||
statuses[s] = statuses.get(s, 0) + 1
|
||||
print(f"Statuses: {statuses}")
|
||||
|
||||
if dry_run:
|
||||
print("\n--dry-run mode: previewing --")
|
||||
else:
|
||||
print(f"\nSyncing via workflow {WF_ID}...")
|
||||
|
||||
succeeded = 0
|
||||
failed = 0
|
||||
for i, a in enumerate(accounts):
|
||||
name = a['name'] or f"(id={a['id']})"
|
||||
if not dry_run:
|
||||
sys.stderr.write(f"\r {i+1}/{len(accounts)}: {name[:40]}...")
|
||||
sys.stderr.flush()
|
||||
|
||||
if sync_account(g, a, dry_run):
|
||||
succeeded += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
if not dry_run:
|
||||
time.sleep(0.15) # avoid rate limiting (~7/sec)
|
||||
|
||||
if not dry_run:
|
||||
sys.stderr.write("\n")
|
||||
|
||||
print(f"\nDone: {succeeded} started, {failed} failed")
|
||||
if dry_run:
|
||||
print("(nothing executed — remove --dry-run to run)")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
154
gaiia/sync_all_radius_groups_workflow.json
Normal file
154
gaiia/sync_all_radius_groups_workflow.json
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
{
|
||||
"name": "Sync All RADIUS Groups",
|
||||
"description": "MANUAL: Syncs RADIUS usergroups for ALL accounts (2 pages x 250 = 500 accounts). Passes actual account status through — ACTIVE, SUSPENDED, INACTIVE, etc.",
|
||||
"trigger": {
|
||||
"type": "MANUAL",
|
||||
"nextSteps": [{ "slug": "fetch-page-1" }]
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "Fetch accounts page 1",
|
||||
"slug": "fetch-page-1",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const data = output.response.accounts;\n return {\n accounts: data.nodes.map((a) => ({\n accountId: a.id,\n status: (a.status?.name || '').toUpperCase(),\n products: (a.billingSubscriptions?.nodes || [])\n .map((s) => s.productVersion?.product?.id)\n .filter(Boolean)\n .filter((id, i, arr) => arr.indexOf(id) === i)\n })),\n hasNextPage: data.pageInfo.hasNextPage,\n endCursor: data.pageInfo.endCursor\n };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query {\n accounts(first: 250) {\n nodes {\n id\n status { name }\n billingSubscriptions {\n nodes { productVersion { product { id } } }\n }\n }\n pageInfo { hasNextPage endCursor }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ secrets, state, utils, variables }) => ({})"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "sync-page-1" }]
|
||||
},
|
||||
{
|
||||
"name": "Sync page 1",
|
||||
"slug": "sync-page-1",
|
||||
"type": "PARALLEL_LOOP",
|
||||
"nodeSlug": "parallel-loop",
|
||||
"maxConcurrentIterations": 10,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "iterable",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['fetch-page-1'].output.accounts"
|
||||
}
|
||||
],
|
||||
"initialSteps": [{ "slug": "call-update-page1" }],
|
||||
"nextSteps": [{ "slug": "need-page-2" }]
|
||||
},
|
||||
{
|
||||
"name": "Call Update RADIUS Account Groups",
|
||||
"slug": "call-update-page1",
|
||||
"type": "GAIIA_START_WORKFLOW_EXECUTION",
|
||||
"nodeSlug": "start-workflow-execution",
|
||||
"parentParallelLoopSlug": "sync-page-1",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "workflowId",
|
||||
"type": "LITERAL",
|
||||
"value": "string:workflow_fLXTNCvridPqwEEXxf3CK1"
|
||||
},
|
||||
{
|
||||
"key": "input",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const acct = state.currentParallelLoopIterations['sync-page-1'];\n return { accountId: acct.accountId, status: acct.status, productIds: acct.products };\n}"
|
||||
},
|
||||
{
|
||||
"key": "fireAndForget",
|
||||
"type": "LITERAL",
|
||||
"value": "boolean:true"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "sync-page-1-end" }]
|
||||
},
|
||||
{
|
||||
"name": "Need page 2?",
|
||||
"slug": "need-page-2",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n return state.steps['fetch-page-1'].output.hasNextPage;\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "fetch-page-2" }]
|
||||
},
|
||||
{
|
||||
"name": "Fetch accounts page 2",
|
||||
"slug": "fetch-page-2",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const nodes = output.response.accounts.nodes;\n if (!nodes || nodes.length === 0) return [];\n return nodes.map((a) => ({\n accountId: a.id,\n status: (a.status?.name || '').toUpperCase(),\n products: (a.billingSubscriptions?.nodes || [])\n .map((s) => s.productVersion?.product?.id)\n .filter(Boolean)\n .filter((id, i, arr) => arr.indexOf(id) === i)\n }));\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query($after: String) {\n accounts(first: 250, after: $after) {\n nodes {\n id\n status { name }\n billingSubscriptions {\n nodes { productVersion { product { id } } }\n }\n }\n pageInfo { hasNextPage endCursor }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const p1 = state.steps['fetch-page-1'].output;\n return p1.hasNextPage ? { after: p1.endCursor } : {};\n}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "if-page-2-has-data" }]
|
||||
},
|
||||
{
|
||||
"name": "Page 2 has data?",
|
||||
"slug": "if-page-2-has-data",
|
||||
"type": "CONDITION",
|
||||
"nodeSlug": "condition",
|
||||
"condition": "({ secrets, state, utils, variables }) => {\n const data = state.steps['fetch-page-2'].output;\n return Array.isArray(data) && data.length > 0;\n}",
|
||||
"elseSteps": [{ "slug": "end" }],
|
||||
"thenSteps": [{ "slug": "sync-page-2" }]
|
||||
},
|
||||
{
|
||||
"name": "Sync page 2",
|
||||
"slug": "sync-page-2",
|
||||
"type": "PARALLEL_LOOP",
|
||||
"nodeSlug": "parallel-loop",
|
||||
"maxConcurrentIterations": 10,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "iterable",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['fetch-page-2'].output"
|
||||
}
|
||||
],
|
||||
"initialSteps": [{ "slug": "call-update-page2" }],
|
||||
"nextSteps": [{ "slug": "end" }]
|
||||
},
|
||||
{
|
||||
"name": "Call Update RADIUS Account Groups (page 2)",
|
||||
"slug": "call-update-page2",
|
||||
"type": "GAIIA_START_WORKFLOW_EXECUTION",
|
||||
"nodeSlug": "start-workflow-execution",
|
||||
"parentParallelLoopSlug": "sync-page-2",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "workflowId",
|
||||
"type": "LITERAL",
|
||||
"value": "string:workflow_fLXTNCvridPqwEEXxf3CK1"
|
||||
},
|
||||
{
|
||||
"key": "input",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const acct = state.currentParallelLoopIterations['sync-page-2'];\n return { accountId: acct.accountId, status: acct.status, productIds: acct.products };\n}"
|
||||
},
|
||||
{
|
||||
"key": "fireAndForget",
|
||||
"type": "LITERAL",
|
||||
"value": "boolean:true"
|
||||
}
|
||||
],
|
||||
"nextSteps": [{ "slug": "sync-page-2-end" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
0
gaiia/tests/__init__.py
Normal file
0
gaiia/tests/__init__.py
Normal file
153
gaiia/tests/test_client.py
Normal file
153
gaiia/tests/test_client.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import httpx
|
||||
import pytest
|
||||
|
||||
from gaiia import (
|
||||
GaiiaAPIError,
|
||||
GaiiaClient,
|
||||
GaiiaMutationError,
|
||||
GaiiaRateLimitedError,
|
||||
)
|
||||
from gaiia.client import API_KEY_HEADER, TIMEZONE_HEADER
|
||||
|
||||
|
||||
def _client(handler):
|
||||
transport = httpx.MockTransport(handler)
|
||||
return GaiiaClient(
|
||||
api_key="gaiia_sk_sbox_test",
|
||||
timezone="America/Chicago",
|
||||
transport=transport,
|
||||
)
|
||||
|
||||
|
||||
def test_query_sends_expected_headers_and_body():
|
||||
captured = {}
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
captured["headers"] = dict(request.headers)
|
||||
captured["body"] = request.read()
|
||||
return httpx.Response(200, json={"data": {"x": 1}})
|
||||
|
||||
with _client(handler) as g:
|
||||
out = g.query("{ x }", {"v": 1})
|
||||
assert out == {"x": 1}
|
||||
assert captured["headers"][API_KEY_HEADER.lower()] == "gaiia_sk_sbox_test"
|
||||
assert captured["headers"][TIMEZONE_HEADER] == "America/Chicago"
|
||||
import json
|
||||
body = json.loads(captured["body"])
|
||||
assert body["query"] == "{ x }"
|
||||
assert body["variables"] == {"v": 1}
|
||||
|
||||
|
||||
def test_top_level_errors_raise_api_error():
|
||||
def handler(request):
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={"errors": [{"message": "bad", "extensions": {"code": "BAD_USER_INPUT"}}]},
|
||||
)
|
||||
|
||||
with _client(handler) as g, pytest.raises(GaiiaAPIError) as exc:
|
||||
g.query("{}")
|
||||
assert exc.value.errors[0].code == "BAD_USER_INPUT"
|
||||
|
||||
|
||||
def test_rate_limited_classifies_separately():
|
||||
def handler(request):
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"errors": [
|
||||
{
|
||||
"message": "too many",
|
||||
"extensions": {
|
||||
"code": "RATE_LIMITED",
|
||||
"limit": 500,
|
||||
"used": 500,
|
||||
"remaining": 0,
|
||||
"retryAt": "2026-06-27T19:01:02.000Z",
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
headers={
|
||||
"X-Rate-Limit-Allowed": "false",
|
||||
"X-Rate-Limit-Limit": "500",
|
||||
"X-Rate-Limit-Used": "500",
|
||||
"X-Rate-Limit-Remaining": "0",
|
||||
},
|
||||
)
|
||||
|
||||
with _client(handler) as g, pytest.raises(GaiiaRateLimitedError) as exc:
|
||||
g.query("{}")
|
||||
assert exc.value.limit == 500
|
||||
assert g.last_rate_limit is not None
|
||||
assert g.last_rate_limit.remaining == 0
|
||||
|
||||
|
||||
def test_mutate_raises_on_payload_errors():
|
||||
def handler(request):
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"data": {
|
||||
"createTicket": {
|
||||
"ticket": None,
|
||||
"errors": [{"code": "TITLE_TOO_LONG", "message": "long"}],
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
with _client(handler) as g, pytest.raises(GaiiaMutationError) as exc:
|
||||
g.mutate("mutation { createTicket { ticket { id } errors { code message } } }", "createTicket")
|
||||
assert exc.value.errors[0]["code"] == "TITLE_TOO_LONG"
|
||||
|
||||
|
||||
def test_iter_nodes_paginates_via_cursor():
|
||||
calls = []
|
||||
|
||||
def handler(request):
|
||||
body = request.read().decode()
|
||||
calls.append(body)
|
||||
if '"after":null' in body.replace(" ", ""):
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"data": {
|
||||
"things": {
|
||||
"nodes": [{"id": 1}, {"id": 2}],
|
||||
"pageInfo": {"hasNextPage": True, "endCursor": "c1"},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"data": {
|
||||
"things": {
|
||||
"nodes": [{"id": 3}],
|
||||
"pageInfo": {"hasNextPage": False, "endCursor": None},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
with _client(handler) as g:
|
||||
ids = [n["id"] for n in g.iter_nodes(
|
||||
"query Q($after: String) { things(first: 2, after: $after) { nodes { id } pageInfo { hasNextPage endCursor } } }",
|
||||
"things",
|
||||
)]
|
||||
assert ids == [1, 2, 3]
|
||||
assert len(calls) == 2
|
||||
|
||||
|
||||
def test_missing_api_key_raises():
|
||||
import os
|
||||
|
||||
saved = os.environ.pop("GAIIA_KEY", None)
|
||||
try:
|
||||
with pytest.raises(ValueError):
|
||||
GaiiaClient()
|
||||
finally:
|
||||
if saved is not None:
|
||||
os.environ["GAIIA_KEY"] = saved
|
||||
45
gaiia/tests/test_globalid.py
Normal file
45
gaiia/tests/test_globalid.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
from uuid import UUID
|
||||
|
||||
import pytest
|
||||
|
||||
from gaiia import decode_global_id, encode_global_id
|
||||
|
||||
|
||||
def test_roundtrip_known_value():
|
||||
type_name = "Account"
|
||||
uuid_str = "3c3b1978-6a68-4a13-bdc2-2d51c8ef7519"
|
||||
gid = encode_global_id(type_name, uuid_str)
|
||||
snake, decoded = decode_global_id(gid)
|
||||
assert snake == "account"
|
||||
assert decoded == uuid_str
|
||||
|
||||
|
||||
def test_camelcase_type_becomes_snake_case():
|
||||
gid = encode_global_id("InventoryItem", "00000000-0000-0000-0000-000000000001")
|
||||
snake, _ = decode_global_id(gid)
|
||||
assert snake == "inventory_item"
|
||||
|
||||
|
||||
def test_accepts_uuid_object():
|
||||
u = UUID("3c3b1978-6a68-4a13-bdc2-2d51c8ef7519")
|
||||
gid = encode_global_id("Account", u)
|
||||
_, decoded = decode_global_id(gid)
|
||||
assert decoded == str(u)
|
||||
|
||||
|
||||
def test_short_id_always_22_chars():
|
||||
gid = encode_global_id("Account", "00000000-0000-0000-0000-000000000001")
|
||||
_, short = gid.split("_", 1)
|
||||
assert len(short) == 22
|
||||
|
||||
|
||||
def test_decode_rejects_garbage():
|
||||
with pytest.raises(ValueError):
|
||||
decode_global_id("no-underscore-here")
|
||||
with pytest.raises(ValueError):
|
||||
decode_global_id("account_!!!invalid!!!")
|
||||
|
||||
|
||||
def test_encode_rejects_bad_uuid():
|
||||
with pytest.raises(ValueError):
|
||||
encode_global_id("Account", "not-a-uuid")
|
||||
43
gaiia/tests/test_pagination.py
Normal file
43
gaiia/tests/test_pagination.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import pytest
|
||||
|
||||
from gaiia.pagination import extract_connection, iter_nodes
|
||||
|
||||
|
||||
def _conn(nodes, has_next=False, end="cur"):
|
||||
return {
|
||||
"nodes": nodes,
|
||||
"pageInfo": {"hasNextPage": has_next, "endCursor": end if has_next else None},
|
||||
}
|
||||
|
||||
|
||||
def test_extract_connection_walks_dotted_path():
|
||||
data = {"a": {"b": _conn([1, 2])}}
|
||||
conn = extract_connection(data, "a.b")
|
||||
assert conn["nodes"] == [1, 2]
|
||||
|
||||
|
||||
def test_extract_connection_missing_path_raises():
|
||||
with pytest.raises(KeyError):
|
||||
extract_connection({"a": {}}, "a.b")
|
||||
|
||||
|
||||
def test_iter_nodes_terminates_on_last_page():
|
||||
pages = [
|
||||
{"things": _conn(["a", "b"], has_next=True, end="x")},
|
||||
{"things": _conn(["c"], has_next=False)},
|
||||
]
|
||||
calls = []
|
||||
|
||||
def fetch(cursor):
|
||||
calls.append(cursor)
|
||||
return pages.pop(0)
|
||||
|
||||
assert list(iter_nodes(fetch, "things")) == ["a", "b", "c"]
|
||||
assert calls == [None, "x"]
|
||||
|
||||
|
||||
def test_iter_nodes_handles_empty():
|
||||
def fetch(cursor):
|
||||
return {"things": _conn([])}
|
||||
|
||||
assert list(iter_nodes(fetch, "things")) == []
|
||||
62
gaiia/tests/test_webhooks.py
Normal file
62
gaiia/tests/test_webhooks.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import hashlib
|
||||
import hmac
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from gaiia import WebhookSignatureError, verify_webhook_signature
|
||||
|
||||
|
||||
def _make_header(secret: str, timestamp: int, body: bytes) -> str:
|
||||
sig = hmac.new(
|
||||
secret.encode(), f"{timestamp}.{body.decode()}".encode(), hashlib.sha256
|
||||
).hexdigest()
|
||||
return f"t={timestamp},v1={sig}"
|
||||
|
||||
|
||||
def test_valid_signature_passes():
|
||||
secret = "whsec_test"
|
||||
body = b'{"hello":"world"}'
|
||||
ts = int(time.time())
|
||||
header = _make_header(secret, ts, body)
|
||||
verify_webhook_signature(header_value=header, raw_body=body, secret=secret)
|
||||
|
||||
|
||||
def test_tampered_body_fails():
|
||||
secret = "whsec_test"
|
||||
body = b'{"hello":"world"}'
|
||||
ts = int(time.time())
|
||||
header = _make_header(secret, ts, body)
|
||||
with pytest.raises(WebhookSignatureError):
|
||||
verify_webhook_signature(
|
||||
header_value=header, raw_body=b'{"hello":"WORLD"}', secret=secret
|
||||
)
|
||||
|
||||
|
||||
def test_old_timestamp_rejected():
|
||||
secret = "whsec_test"
|
||||
body = b'{"x":1}'
|
||||
ts = int(time.time()) - 3600
|
||||
header = _make_header(secret, ts, body)
|
||||
with pytest.raises(WebhookSignatureError):
|
||||
verify_webhook_signature(
|
||||
header_value=header, raw_body=body, secret=secret, tolerance_seconds=60
|
||||
)
|
||||
|
||||
|
||||
def test_multiple_signatures_one_match():
|
||||
secret = "whsec_test"
|
||||
body = b"abc"
|
||||
ts = int(time.time())
|
||||
real = _make_header(secret, ts, body).split("v1=")[1]
|
||||
header = f"t={ts},v1=ffffffff,v1={real}"
|
||||
verify_webhook_signature(header_value=header, raw_body=body, secret=secret)
|
||||
|
||||
|
||||
def test_missing_components():
|
||||
with pytest.raises(WebhookSignatureError):
|
||||
verify_webhook_signature(header_value="", raw_body=b"", secret="x")
|
||||
with pytest.raises(WebhookSignatureError):
|
||||
verify_webhook_signature(header_value="v1=abc", raw_body=b"", secret="x")
|
||||
with pytest.raises(WebhookSignatureError):
|
||||
verify_webhook_signature(header_value="t=123", raw_body=b"", secret="x")
|
||||
108
gaiia/update_preseem_on_ip_change.json
Normal file
108
gaiia/update_preseem_on_ip_change.json
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"steps": [
|
||||
{
|
||||
"name": "Find inventory item",
|
||||
"slug": "find-inventory-item",
|
||||
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
||||
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
||||
"allowSkipExecution": false,
|
||||
"outputMapper": "({ output }) => {\n const assignee = output.response.inventoryItem?.assignation?.assignee;\n if (!assignee || assignee.__typename !== 'Account') {\n workflow.fail('Inventory item is not assigned to an account.', 'NO_ACCOUNT');\n }\n return { id: assignee.id, gaiiaId: assignee.readableId };\n}",
|
||||
"inputs": [
|
||||
{
|
||||
"key": "query",
|
||||
"type": "LITERAL",
|
||||
"value": "string:query IpAssignmentWorkflowInventoryItemQuery($id: ID!) {\n inventoryItem(id: $id) {\n id\n assignation {\n assignee {\n ... on Account { id readableId }\n }\n }\n }\n}"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => ({ id: state.input.objectId })"
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
{
|
||||
"slug": "find-account-cpes"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Find account CPEs",
|
||||
"slug": "find-account-cpes",
|
||||
"type": "GAIIA_FIND_ACCOUNT_CPES",
|
||||
"nodeSlug": "find-account-cpes",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "accountId",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['find-inventory-item'].output.id"
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
{
|
||||
"slug": "find-account-internet-plans"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Find account Internet plans",
|
||||
"slug": "find-account-internet-plans",
|
||||
"type": "GAIIA_FIND_ACCOUNT_INTERNET_PLANS",
|
||||
"nodeSlug": "find-account-internet-plans",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "accountId",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => state.steps['find-inventory-item'].output.id"
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
{
|
||||
"slug": "preseem-update-service"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Preseem update service",
|
||||
"slug": "preseem-update-service",
|
||||
"type": "PRESEEM_REST_REQUEST",
|
||||
"nodeSlug": "preseem-rest-request",
|
||||
"allowSkipExecution": false,
|
||||
"inputs": [
|
||||
{
|
||||
"key": "body",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => {\n const { gaiiaId } = state.steps['find-inventory-item'].output;\n const [{ slug }] = state.steps['find-account-internet-plans'].output.internetPlans;\n const cpes = state.steps['find-account-cpes'].output.accountCpe;\n const eventMac = state.input.payload.macAddress;\n const macAddresses = [\n ...new Set([\n ...cpes.map(({ macAddress }) => macAddress),\n eventMac\n ])\n ];\n return {\n id: String(gaiiaId),\n attachments: macAddresses\n .filter(Boolean)\n .map((macAddress) => ({ cpe_mac: macAddress.toLowerCase() })),\n account: String(gaiiaId),\n package: slug\n };\n }"
|
||||
},
|
||||
{
|
||||
"key": "method",
|
||||
"type": "LITERAL",
|
||||
"value": "string:PUT"
|
||||
},
|
||||
{
|
||||
"key": "path",
|
||||
"type": "FUNCTION",
|
||||
"value": "({ state }) => /services/${state.steps['find-inventory-item'].output.gaiiaId}"
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
{
|
||||
"slug": "end"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trigger": {
|
||||
"nextSteps": [
|
||||
{
|
||||
"slug": "find-inventory-item"
|
||||
}
|
||||
],
|
||||
"type": "EVENT",
|
||||
"events": [
|
||||
"inventory_item.ip_address_assigned",
|
||||
"inventory_item.ip_address_unassigned"
|
||||
]
|
||||
}
|
||||
}
|
||||
502
gaiia/uv.lock
generated
Normal file
502
gaiia/uv.lock
generated
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.10"
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.15'",
|
||||
"python_full_version < '3.15'",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.13.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "idna" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ast-serialize"
|
||||
version = "0.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a9/9d/912fefab0e30aee6a3af8a62bbea4a81b29afa4ba2c973d31170620a26de/ast_serialize-0.3.0.tar.gz", hash = "sha256:1bc3ca09a63a021376527c4e938deedd11d11d675ce850e6f9c7487f5889992b", size = 60689, upload-time = "2026-04-30T23:24:48.104Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/57/a54d4de491d6cdd7a4e4b0952cc3ca9f60dcefa7b5fb48d6d492debe1649/ast_serialize-0.3.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:3a867927df59f76a18dc1d874a0b2c079b42c58972dca637905576deb0912e14", size = 1182966, upload-time = "2026-04-30T23:23:57.376Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/9e/a5db014bb0f91b209236b57c429389e31290c0093532b8436d577699b2fa/ast_serialize-0.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a6fb063bf040abf8321e7b8113a0554eda445ffc508aa51287f8808886a5ae22", size = 1171316, upload-time = "2026-04-30T23:23:59.63Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/59/fd55133e478c4326f60a11df02573bf7ccb2ac685810b50f1803d0f68053/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5075cd8482573d743586779e5f9b652a015e37d4e95132d7e5a9bc5c8f483d8f", size = 1232234, upload-time = "2026-04-30T23:24:01.168Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/79/0ca1d26357ecb4a697d74d00b73ef3137f24c140424125393a0de820eb09/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:41560b27794f4553b0f77811e9fb325b77db4a2b39018d437e09932275306e66", size = 1233437, upload-time = "2026-04-30T23:24:03.151Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/3e/7078ec94dd6e124b8e028ac77016a4f13c83fa1c145790f2e68f3816998b/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b967c01ca74909c5d90e0fe4393401e2cc5da5ebd9a6262a19e45ffd3757dec8", size = 1440188, upload-time = "2026-04-30T23:24:04.717Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/16/cca7195ef55a012f8013c3442afa91d287a0a36dcf88b480b262475135b3/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:424ebb8f46cd993f7cec4009d119312d8433dd90e6b0df0499cd2c91bdcc5af9", size = 1254211, upload-time = "2026-04-30T23:24:06.18Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/0f/f3d4dfae67dee6580534361a6343367d34217e7d25cff858bd1d8f03b8ed/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d14b1d566b56e2ee70b11fec1de7e0b94ec7cd83717ec7d189967841a361190e", size = 1255973, upload-time = "2026-04-30T23:24:07.772Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/41/55fbfe02c42f40fbe3e74eda167d977d555ff720ce1abfa08515236efd88/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ba30b18735f047ec11103d1ab92f4789cf1fea1e0dc89b04a2f5a0632fd79de", size = 1298629, upload-time = "2026-04-30T23:24:09.4Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/36/7d2501cacc7989fb8504aa9da2a2022a174200a59d4e6639de4367a57fdd/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e6ea0754cb7b0f682ebb005ffb0d18f8d17993490d9c289863cd69cacc4ab8df", size = 1408435, upload-time = "2026-04-30T23:24:11.013Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/e7/54e3b469c3fa0bf9cd532fa643d1d33b73303f8d70beac3e366b68dd64b7/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a0c5aa1073a5ba7b2abaa4b54abe8b8d75c4d1e2d54a2ff70b0ca6222fea5728", size = 1508174, upload-time = "2026-04-30T23:24:12.635Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/2a/9b9621865b02c60539e26d9b114a312b4fa46aa703e33e79317174bfea21/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:4e52650d834c1ea7791969a361de2c54c13b2fb4c519ec79445fa8b9021a147d", size = 1502354, upload-time = "2026-04-30T23:24:14.186Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/dd/f138bc5c43b0c414fdd12eefe15677839323078b6e75301ad7f96cd26d45/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15bd6af3f136c61dae27805eb6b8f3269e85a545c4c27ffe9e530ead78d2b36d", size = 1450504, upload-time = "2026-04-30T23:24:16.076Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/cf/97ef9e1c315601db74365955c8edd3292e3055500d6317602815dbdf08ae/ast_serialize-0.3.0-cp314-cp314t-win32.whl", hash = "sha256:d188bfe37b674b49708497683051d4b571366a668799c9b8e8a94513694969d9", size = 1058662, upload-time = "2026-04-30T23:24:17.535Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/d6/e2c3483c31580fdb623f92ad38d2f856cde4b9205a3e6bd84760f3de7d82/ast_serialize-0.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5832c2fdf8f8a6cf682b4cfcf677f5eaf39b4ddbc490f5480cfccdd1e7ce8fa1", size = 1100349, upload-time = "2026-04-30T23:24:18.992Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/89/29abcb1fe18a429cda60c6e0bbd1d6e90499339842a2f548d7567542357e/ast_serialize-0.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:670f177188d128fb7f9f15b5ad0e1b553d22c34e3f584dcb83eb8077600437f0", size = 1072895, upload-time = "2026-04-30T23:24:20.706Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/93/72abad83966ed6235647c9f956417dc1e17e997696388521910e3d1fa3f4/ast_serialize-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ec2fafa5e4313cc8feed96e436ebe19ac7bc6fa41fbc2827e826c48b9e4c3a9", size = 1190024, upload-time = "2026-04-30T23:24:22.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/4f/eb88584b2f0234e581762011208ca203252bf6c98e59b4769daa571f3576/ast_serialize-0.3.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef6d3c08b7b4cd29b48410338e134764a00e76d25841eb02c1084e868c888ecc", size = 1178633, upload-time = "2026-04-30T23:24:24.35Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/51/cf1ec1ff3e616373d0dcbd5fad502e0029dc541f13ab642259762a7d127f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d841424f41b886e98044abc80769c14a956e6e5ccd5fb5b0d9f5ead72be18a4", size = 1241351, upload-time = "2026-04-30T23:24:25.987Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/44/68fcf50478cf1093f2d423f034ae06453122c8b415d8e21a44668eca485d/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d21453734ad39367ede5d37efe4f59f830ce1c09f432fc72a90e368f77a4a3e7", size = 1239582, upload-time = "2026-04-30T23:24:27.808Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/c1/a6c9fa284eceb5fc6f21347e968445a051d7ca2c4d34e6a04314646dbcee/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5e110cdce2a347e1dd987529c88ef54d26f67848dce3eba1b3b2cc2cf085c94", size = 1448853, upload-time = "2026-04-30T23:24:29.534Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/5f/8ad3829a09e4e8c5328a53ce7d4711d660944e3e164c5f6abcc2c8f27167/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6e23a98e57560a055f5c4b68700a0fd5ce483d2814c23140b3638c7f5d1e61", size = 1262204, upload-time = "2026-04-30T23:24:31.482Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/13/44aa28d97f10e25247e8576b5f6b2795d4fa1a80acc88acc942c508d06f7/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c9e763d70293d65ce1e1ea8c943140c68d0953f0268c7ee0998f2e07f77dd0", size = 1266458, upload-time = "2026-04-30T23:24:33.088Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/58/b3a8be3777cd3744324fd5cec0d80d37cd96fc7cbb0fb010e03dff1e870f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4388a1796c228f1ce5c391426f7d21a0003ad3b47f677dbeded9bd1a85c7209f", size = 1308700, upload-time = "2026-04-30T23:24:34.657Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/03/f8312d6b57f5471a9dc7946f22b8798a1fc296d38c25766223aacadec42c/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5283cdcc0c64c3d8b9b688dc6aaa012d9c0cf1380a7f774a6bae6a1c01b3205a", size = 1416724, upload-time = "2026-04-30T23:24:36.562Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/5d/13fc3789a7abac00559da2e2e9f386db4612aa1f84fc53d09bf714c37545/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f5ef88cc5842a5d7a6ac09dc0d5fc2c98f5d276c1f076f866d55047ce886785b", size = 1515441, upload-time = "2026-04-30T23:24:38.018Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/b9/7ab43fc7a23b1f970281093228f5f79bed6edeed7a3e672bde6d7a832a58/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cc14bf402bdc0978594ecce783793de2c7470cd4f5cd7eb286ca97ed8ff7cba9", size = 1510522, upload-time = "2026-04-30T23:24:39.798Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/ec/d75fc2b788d319f1fad77c14156896f31afdfc68af85b505e5bdebcb9592/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11eae0cf1b7b3e0678133cc2daa974ea972caf02eb4b3aa062af6fa9acd52c57", size = 1460917, upload-time = "2026-04-30T23:24:41.305Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/74/f99c81193a2725911e1911ae567ed27c2f2419332c7f3537366f9d238cac/ast_serialize-0.3.0-cp39-abi3-win32.whl", hash = "sha256:2db3dd99de5e6a5a11d7dda73de8750eb6e5baaf25245adf7bdcfe64b6108ae2", size = 1067804, upload-time = "2026-04-30T23:24:43.091Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/81/76af00c47daa151e89f98ae21fbbcb2840aaa9f5766579c4da76a3c57188/ast_serialize-0.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:a2cd125adccf7969470621905d302750cd25951f22ea430d9a25b7be031e5549", size = 1105561, upload-time = "2026-04-30T23:24:44.578Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/46/d3ec57ad500f598d1554bd14ce4df615960549ab2844961bc4e1f5fbd174/ast_serialize-0.3.0-cp39-abi3-win_arm64.whl", hash = "sha256:0dd00da29985f15f50dc35728b7e1e7c84507bccfea1d9914738530f1c72238a", size = 1077165, upload-time = "2026-04-30T23:24:46.377Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backports-asyncio-runner"
|
||||
version = "1.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.4.22"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gaiia"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
dev = [
|
||||
{ name = "mypy" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "respx" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "httpx", specifier = ">=0.27" },
|
||||
{ name = "mypy", marker = "extra == 'dev'", specifier = ">=1.10" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23" },
|
||||
{ name = "respx", marker = "extra == 'dev'", specifier = ">=0.21" },
|
||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.5" },
|
||||
]
|
||||
provides-extras = ["dev"]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/05/b1/efac073e0c297ecf2fb33c346989a529d4e19164f1759102dee5953ee17e/idna-3.14.tar.gz", hash = "sha256:466d810d7a2cc1022bea9b037c39728d51ae7dad40d480fc9b7d7ecf98ba8ee3", size = 198272, upload-time = "2026-05-10T20:32:15.935Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/3c/3f62dee257eb3d6b2c1ef2a09d36d9793c7111156a73b5654d2c2305e5ce/idna-3.14-py3-none-any.whl", hash = "sha256:e677eaf072e290f7b725f9acf0b3a2bd55f9fd6f7c70abe5f0e34823d0accf69", size = 72184, upload-time = "2026-05-10T20:32:14.295Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "librt"
|
||||
version = "0.11.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/83/10/37fd9e9ba96cb0bd742dfb20fc3d082e54bdbec759d7300df927f360ef07/librt-0.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6e94ebfcfa2d5e9926d6c3b9aa4617ffc42a845b4321fb84021b872358c82a0f", size = 141706, upload-time = "2026-05-10T18:15:16.129Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/72/1b1466f358e4a0b728051f69bc27e67b432c6eaa2e05b88db49d3785ae0d/librt-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae627397a2f351560440d872d6f7c8dbb4072e57868e7b2fc5b8b430fe489d45", size = 142605, upload-time = "2026-05-10T18:15:18.148Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/85/ed26dd2f6bc9a0baf48306433e579e8d354d70b2bcb78134ed950a5d0e1e/librt-0.11.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc329359321b67d24efdf4bc69012b0597001649544db662c001db5a0184794c", size = 476555, upload-time = "2026-05-10T18:15:19.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/fe/11891191c0e0a3fd617724e891f6e67a71a7658974a892b9a9a97fdb2977/librt-0.11.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:7e82e642ab0f7608ce2fe53d76ca2280a9ee33a1b06556142c7c6fe80a86fc33", size = 468434, upload-time = "2026-05-10T18:15:20.87Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/50/5ec949d7f9ce1a07af903aa3e13abb98b717923bdead6e719b2f824ccc07/librt-0.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88145c15c67731d54283d135b03244028c750cc9edc334a96a4f5950ebdb2884", size = 496918, upload-time = "2026-05-10T18:15:22.616Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/c4/177336c7524e34875a38bf668e88b193a6723a4eb4045d07f74df6e1506c/librt-0.11.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9d36a51b3d93320b686588e27123f4995804dbf1bce81df78c02fc3c6eea9280", size = 490334, upload-time = "2026-05-10T18:15:24.2Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/1f/da3112f7569eda3b49f9a2629bae1fe059812b6085df16c885f6454dff49/librt-0.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3ac06a2a8b246327f11e186a53a100a4d5c7ed52346367e5ec751d51586c", size = 511287, upload-time = "2026-05-10T18:15:26.226Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/94/03fec301522e172d105581431223be56b27594ff46440ebfbb658a3735d5/librt-0.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:461bbceede621f1ffb8839755f8663e886087ee7af16294cab7fb4d782c62eeb", size = 517202, upload-time = "2026-05-10T18:15:27.965Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/6e/339f6e5a7b413ce014f1917a756dae630fe59cc99f34153205b1cb540901/librt-0.11.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0cad8a4d6a8ff03c9b76f9414caccd78e7cfbc8a2e12fa334d8e1d9932753783", size = 497517, upload-time = "2026-05-10T18:15:29.614Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/43/acdd5ce317cb46e8253ca9bfbdb8b12e68a24d745949336a7f3d5fb79ba0/librt-0.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f37aa505b3cf60701562eddb32df74b12a9e380c207fd8b06dd157a943ac7ea0", size = 538878, upload-time = "2026-05-10T18:15:30.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/b5/7a25bb12e3172839f647f196b3e988318b7bb1ca7501732a225c4dce2ec0/librt-0.11.0-cp310-cp310-win32.whl", hash = "sha256:94663a21534637f0e787ec2a2a756022df6e5b7b2335a5cdd7d8e33d68a2af89", size = 100070, upload-time = "2026-05-10T18:15:32.551Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/0d/ebbcf4d77999c02c937b05d2b90ff4cd4dcc7e9a365ba132329ac1fe7a0f/librt-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:dec7db73758c2b54953fd8b7fe348c45188fe26b39ee18446196edd08453a5d4", size = 117918, upload-time = "2026-05-10T18:15:33.678Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/87/2bf31fe17587b29e3f93ec31421e2b1e1c3e349b8bf6c7c313dbad1d5340/librt-0.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29", size = 141092, upload-time = "2026-05-10T18:15:34.795Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/08/5c5bf772920b7ebac6e32bc91a643e0ab3870199c0b542356d3baa83970a/librt-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9", size = 142035, upload-time = "2026-05-10T18:15:36.242Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/20/662a03d254e5b000d838e8b345d83303ddb768c080fd488e40634c0fa66b/librt-0.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5", size = 475022, upload-time = "2026-05-10T18:15:37.56Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/f3/aa81523e45184c6ec23dc7f63263362ec55f80a09d424c012359ecbe7e35/librt-0.11.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b", size = 467273, upload-time = "2026-05-10T18:15:39.182Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/6f/59c74b560ca8853834d5501d589c8a2519f4184f273a085ffd0f37a1cc47/librt-0.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89", size = 497083, upload-time = "2026-05-10T18:15:40.634Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/7b/5aa4d2c9600a719401160bf7055417df0b2a47439b9d88286ce45e56b65f/librt-0.11.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc", size = 489139, upload-time = "2026-05-10T18:15:41.934Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/31/9143803d7da6856a69153785768c4936864430eec0fd9461c3ea527d9922/librt-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5", size = 508442, upload-time = "2026-05-10T18:15:43.206Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/5a/bce08184488426bda4ccc2c4964ac048c8f68ae89bd7120082eef4233cfd/librt-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7", size = 514230, upload-time = "2026-05-10T18:15:44.761Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/8c/bb5e213d254b7505a0e658da199d8ab719086632ce09eef311ab27976523/librt-0.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d", size = 494231, upload-time = "2026-05-10T18:15:46.308Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/fb/541cdad5b1ab1300398c74c4c9a497b88e5074c21b1244c8f49731d3a284/librt-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412", size = 537585, upload-time = "2026-05-10T18:15:47.629Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/f2/464bb69295c320cb06bddb4f14a4ec67934ee14b2bffb12b19fb7ab287ba/librt-0.11.0-cp311-cp311-win32.whl", hash = "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d", size = 100509, upload-time = "2026-05-10T18:15:49.157Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/e7/a17ee1788f9e4fbf548c19f4afa07c92089b9e24fef6cb2410863781ef4c/librt-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73", size = 118628, upload-time = "2026-05-10T18:15:50.345Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/c7/6c766214f9f9903bcfcfbef97d807af8d8f5aa3502d247858ab17582d212/librt-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c", size = 103122, upload-time = "2026-05-10T18:15:52.068Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/d0/07c77e067f0838949b43bd89232c29d72efebb9d2801a9750184eb706b71/librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", size = 144147, upload-time = "2026-05-10T18:15:53.227Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/24/8493538fa4f62f982686398a5b8f68008138a75086abdea19ade64bf4255/librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", size = 143614, upload-time = "2026-05-10T18:15:54.657Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/1e/f8bad050810d9171f34a1648ed910e56814c2ba61639f2bd53c6377ae24b/librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", size = 485538, upload-time = "2026-05-10T18:15:56.117Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/fe/3594ebfbaf03084ba4b120c9ba5c3183fd938a48725e9bbe6ff0a5159ad8/librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", size = 479623, upload-time = "2026-05-10T18:15:57.544Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/da/5d1876984b3746c85dbd219dbfcb73c85f54ee263fd32e5b2a632ec14571/librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", size = 513082, upload-time = "2026-05-10T18:15:58.805Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/6e/55bdf5d5ca00c3e18430690bf2c953d8d3ffd3c337418173d33dec985dc9/librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", size = 508105, upload-time = "2026-05-10T18:16:00.2Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/10/f1f23a7c595ee90ece4d35c851e5d104b1311a887ed1b4ac4c35bbd13da8/librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", size = 522268, upload-time = "2026-05-10T18:16:01.708Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/02/5720f5697a7f54b78b3aefbe20df3a48cedcff1276618c4aa481177942ed/librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", size = 527348, upload-time = "2026-05-10T18:16:03.496Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/db/b4a47c6f91db4ff76348a0b3dd0cc65e090a078b765a810a62ff9434c3d3/librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", size = 516294, upload-time = "2026-05-10T18:16:05.173Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/58/9384b2f4eb1ed1d273d40948a7c5c4b2360213b402ef3be4641c06299f9c/librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", size = 553608, upload-time = "2026-05-10T18:16:06.839Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/7b/5aa8848a7c6a9278c79375146da1812e695754ceec5f005e6043461a7315/librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", size = 101879, upload-time = "2026-05-10T18:16:08.103Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/33/8a745436944947575b584231750a41417de1a38cf6a2e9251d1065651c09/librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", size = 119831, upload-time = "2026-05-10T18:16:09.174Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/67/a6739ac96e28b7855808bdb0370e250606104a859750d209e5a0716fe7ab/librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", size = 103470, upload-time = "2026-05-10T18:16:10.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345, upload-time = "2026-05-10T18:16:30.674Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131, upload-time = "2026-05-10T18:16:32.037Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024, upload-time = "2026-05-10T18:16:33.493Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221, upload-time = "2026-05-10T18:16:34.864Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174, upload-time = "2026-05-10T18:16:36.705Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216, upload-time = "2026-05-10T18:16:38.418Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921, upload-time = "2026-05-10T18:16:39.848Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850, upload-time = "2026-05-10T18:16:41.471Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237, upload-time = "2026-05-10T18:16:43.15Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261, upload-time = "2026-05-10T18:16:44.408Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965, upload-time = "2026-05-10T18:16:46.039Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151, upload-time = "2026-05-10T18:16:47.133Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850, upload-time = "2026-05-10T18:16:48.597Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138, upload-time = "2026-05-10T18:16:49.839Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976, upload-time = "2026-05-10T18:16:51.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927, upload-time = "2026-05-10T18:16:52.632Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698, upload-time = "2026-05-10T18:16:53.934Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162, upload-time = "2026-05-10T18:16:55.589Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494, upload-time = "2026-05-10T18:16:56.975Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858, upload-time = "2026-05-10T18:16:58.374Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318, upload-time = "2026-05-10T18:16:59.676Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115, upload-time = "2026-05-10T18:17:01.007Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918, upload-time = "2026-05-10T18:17:02.682Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562, upload-time = "2026-05-10T18:17:03.99Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327, upload-time = "2026-05-10T18:17:05.465Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572, upload-time = "2026-05-10T18:17:06.809Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "2.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "ast-serialize" },
|
||||
{ name = "librt", marker = "platform_python_implementation != 'PyPy'" },
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/71/d351dca3e9b30da2328ee9d445c88b8388072808ebfbc49eb69d30b67749/mypy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:11a6beb180257a805961aea9ec591bbd0bd17f1e18d35b8456d57aee5bedfedc", size = 14778792, upload-time = "2026-05-11T18:36:23.605Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/45/7d51594b644c17c0bcf74ed8cd5fc33b324276d708e8506f220b70dab9d9/mypy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ef78c1d306bbf9a8a12f526c44902c9c28dffd6c52c52bf6a72641ce18d3849", size = 13645739, upload-time = "2026-05-11T18:37:22.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/01/455c31b170e9468265074840bf18863a8482a24103fdaabe4e199392aa5f/mypy-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c209a90853081ff01d01ee895cafe10f7db1474e0d95beaeef0f6c1db9119bbd", size = 14074199, upload-time = "2026-05-11T18:35:09.292Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/5a/93093f0b29a9e982deafde698f740a2eb2e05886e79ccf0594c7fd5413a3/mypy-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47cebf61abde7c088a4e27718a8b13a81655686b2e9c251f5c0915a802248166", size = 14953128, upload-time = "2026-05-11T18:31:57.678Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/2f/a196f5331d96170ad3d28f144d2aba690d4b2911381f68d51e489c7ab82a/mypy-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d57a90ae5e872138a425ec328edbc9b235d1934c4377881a33ec05b341acc9a8", size = 15249378, upload-time = "2026-05-11T18:33:00.101Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/de/94d321cc12da9f71341ac0c270efbed5c725750c7b4c334d957de9a087d9/mypy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:aea7f7a8a55b459c34275fc468ada6ca7c173a5e43a68f5dbe588a563d8a06b8", size = 11060994, upload-time = "2026-05-11T18:33:18.848Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/62/0c27ca55219a7c764a7fb88c7bb2b7b2f9780ade8bbf16bc8ed8400eef6b/mypy-2.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:c989640253f0d76843e9c6c1bbf4bd48c5e85ada61bde4beb37cb3eca035685e", size = 9976743, upload-time = "2026-05-11T18:31:25.554Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/a1/639f3024794a2a15899cb90707fe02e044c4412794c39c5769fd3df2e2ef/mypy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a683016b16fe2f572dc04c72be7ee0504ac1605a265d0200f5cea695fb788f41", size = 14691685, upload-time = "2026-05-11T18:33:27.973Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/08/9a585dea4325f20d8b80dc78623fa50d1fd2173b710f6237afd6ba6ab39b/mypy-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a293c534adb55271fef24a26da04b855540a8c13cc07bc5917b9fd2c394f2ca", size = 13555165, upload-time = "2026-05-11T18:32:16.107Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/dc/7c42cc9c6cb01e8eb09961f1f738741d3e9c7e9d5c5b30ec69222625cd5f/mypy-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7406f4d048e71e576f5356d317e5b0a9e666dfd966bd99f9d14ca06e1a341538", size = 13994376, upload-time = "2026-05-11T18:32:39.256Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/fa/285946c33bce716e082c11dfeee9ee196eaf1f5042efb3581a31f9f205e4/mypy-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0210d626fc8b31ccc90233754c7bc90e1f43205e85d96387f7db1285b55c398", size = 14864618, upload-time = "2026-05-11T18:34:49.765Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/83/82397f48af6c27e295d57979ded8490c9829040152cf7571b2f026aeb9a0/mypy-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3712c20deed54e814eaaa825603bada8ea1c390670a397c95b98405347acc563", size = 15102063, upload-time = "2026-05-11T18:34:05.855Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/68/b02dec39057b88eb03dc0aa854732e26e8361f34f9d0e20c7614967d1eba/mypy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fcaa0e479066e31f7cceb6a3bea39cb22b2ff51a6b2f24f193d19179ba17c389", size = 11060564, upload-time = "2026-05-11T18:35:36.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/a8/ea3dcbef31f99b634f2ee23bb0321cbc8c1b388b76a861eb849f13c347dc/mypy-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:0b1a5260c95aa443083f9ed3592662941951bca3d4ca224a5dc517c38b7cf666", size = 9966983, upload-time = "2026-05-11T18:37:14.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/b1/55861beb5c339b44f9a2ba92df9e2cb1eeb4ae1eee674cdf7772c797778b/mypy-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af", size = 14874381, upload-time = "2026-05-11T18:37:31.784Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/b3/b7f770114b7d0ac92d0f76e8d93c2780844a70488a90e91821927850da86/mypy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6", size = 13665501, upload-time = "2026-05-11T18:34:23.063Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/f3/8ae2037967e2126689a0c11d99e2b707134a565191e92c60ca2572aec60a/mypy-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211", size = 14045750, upload-time = "2026-05-11T18:31:48.151Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/32/615eb5911859e43d054941b0d0a7d06cfa2870eba86529cf385b052b111c/mypy-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b", size = 15061630, upload-time = "2026-05-11T18:37:06.898Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/03/4eafbfff8bfab1b87082741eae6e6a624028c984e6708b73bce2a8570c9d/mypy-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22", size = 15288831, upload-time = "2026-05-11T18:31:18.07Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/ee/919661478e5891a3c96e549c036e467e64563ab85995b10c53c8358e16a3/mypy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b", size = 11135228, upload-time = "2026-05-11T18:34:31.23Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/0a/6a12b9782ca0831a553192f351679f4548abc9d19a7cc93bb7feb02084c7/mypy-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8", size = 10040684, upload-time = "2026-05-11T18:36:48.199Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/ca/b279a672e874aedd5498ae25f722dacc8aa86bbffb939b3f97cbb1cf6686/mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", size = 14848422, upload-time = "2026-05-11T18:35:45.984Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/e6/3efe56c631d959b9b4454e208b0ac4b7f4f58b404c89f8bec7b49efdfc21/mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", size = 13677374, upload-time = "2026-05-11T18:36:57.188Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/7f/8107ea87a44fd1f1b59882442f033c9c3488c127201b1d1d15f1cbd6022e/mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", size = 14055743, upload-time = "2026-05-11T18:35:18.361Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/4d/b6d34db183133b83761b9199a82d31557cdbb70a380d8c3b3438e11882a3/mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", size = 15020937, upload-time = "2026-05-11T18:34:59.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/d7/f08360c691d758acb02f45022c34d98b92892f4ea756644e1000d4b9f3d8/mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", size = 15253371, upload-time = "2026-05-11T18:36:41.081Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/1b/09460a13719530a19bce27bd3bc8449e83569dd2ba7faf51c9c3c30c0b61/mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", size = 11326429, upload-time = "2026-05-11T18:34:13.526Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/62/75dbf0f82f7b6680340efc614af29dd0b3c17b8a4f1cd09b8bd2fd6bc814/mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", size = 10218799, upload-time = "2026-05-11T18:32:23.491Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/66/caca04ed7d972fb6eb6dd1ccd6df1de5c38fae8c5b3dc1c4e8e0d85ee6b9/mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", size = 15923458, upload-time = "2026-05-11T18:35:28.64Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/52/2d90cbe49d014b13ed7ff337930c30bad35893fe38a1e4641e756bb62191/mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780", size = 14757697, upload-time = "2026-05-11T18:36:14.208Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/37/d98f4a14e081b238992d0ed96b6d39c7cc0148c9699eb71eaa68629665ea/mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", size = 15405638, upload-time = "2026-05-11T18:33:48.249Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/c2/15c46613b24a84fad2aea1248bf9619b99c2767ae9071fe224c179a0b7d4/mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", size = 16215852, upload-time = "2026-05-11T18:32:50.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/90/9c16a57f482c76d25f6379762b56bbf65c711d8158cf271fb2802cfb0640/mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", size = 16452695, upload-time = "2026-05-11T18:33:38.182Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/4c/215a4eeb63cacc5f17f516691ea7285d11e249802b942476bff15922a314/mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", size = 12866622, upload-time = "2026-05-11T18:34:39.945Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/50/1043e1db5f455ffe4c9ab22747cd8ca2bc492b1e4f4e21b130a44ee2b217/mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", size = 10610798, upload-time = "2026-05-11T18:36:31.444Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "26.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "1.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.20.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-asyncio"
|
||||
version = "1.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" },
|
||||
{ name = "pytest" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "respx"
|
||||
version = "0.23.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/98/4e55c9c486404ec12373708d015ebce157966965a5ebe7f28ff2c784d41b/respx-0.23.1.tar.gz", hash = "sha256:242dcc6ce6b5b9bf621f5870c82a63997e8e82bc7c947f9ffe272b8f3dd5a780", size = 29243, upload-time = "2026-04-08T14:37:16.008Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/4a/221da6ca167db45693d8d26c7dc79ccfc978a440251bf6721c9aaf251ac0/respx-0.23.1-py2.py3-none-any.whl", hash = "sha256:b18004b029935384bccfa6d7d9d74b4ec9af73a081cc28600fffc0447f4b8c1a", size = 25557, upload-time = "2026-04-08T14:37:14.613Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.15.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.4.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||
]
|
||||
6980
gaiia/workflows_backup_2026-07-10_125815.json
Normal file
6980
gaiia/workflows_backup_2026-07-10_125815.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
|||
# 2026-05-14 13:40:52 by RouterOS 7.21.4
|
||||
# 2026-07-10 10:54:21 by RouterOS 7.21.4
|
||||
# software id = K4QG-8NQV
|
||||
#
|
||||
# model = RB5009UG+S+
|
||||
|
|
@ -218,15 +218,15 @@ add add-arp=yes address-pool=mgmt interface=management lease-script="{\
|
|||
/ip smb users
|
||||
set [ find default=yes ] disabled=yes
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=494-cust-pd-1 prefix=2606:1c80:1a01::/48 prefix-length=56
|
||||
/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 dhcpv6-pd-pool=494-cust-pd-1 dns-server=\
|
||||
204.110.191.240,204.110.191.20 local-address=100.64.175.254 name=494 \
|
||||
on-down="{\
|
||||
204.110.191.240,204.110.191.250 idle-timeout=1h 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\"\
|
||||
|
|
@ -334,8 +334,9 @@ add change-tcp-mss=yes dhcpv6-pd-pool=494-cust-pd-1 dns-server=\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" remote-address=cgnat remote-ipv6-prefix-pool=494-cust-pd-1 use-upnp=\
|
||||
no
|
||||
\n" only-one=yes remote-address=cgnat remote-ipv6-prefix-pool=\
|
||||
494-cust-pd-1 use-upnp=no
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/queue type
|
||||
add kind=fq-codel name=fq-codel
|
||||
/queue interface
|
||||
|
|
@ -355,10 +356,10 @@ add as=393837 name=bgp-instance-1 router-id=10.254.254.111
|
|||
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
|
||||
add in-filter-chain=ospf-in name=default-v2 originate-default=never \
|
||||
out-filter-chain=ospf-out redistribute=connected router-id=id-1
|
||||
/routing ospf area
|
||||
add disabled=no instance=ospf-instance-1 name=ospf-area-1
|
||||
add instance=default-v2 name=backbone-v2
|
||||
/snmp community
|
||||
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||
kdyyJrT0Mm
|
||||
|
|
@ -389,8 +390,8 @@ set tcp-syncookies=yes
|
|||
/ipv6 settings
|
||||
set accept-router-advertisements=no
|
||||
/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
|
||||
add authentication=mschap2 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
|
||||
|
|
@ -403,22 +404,35 @@ add address=100.64.175.254/20 interface=494 network=100.64.160.0
|
|||
add interface=ether1
|
||||
# Interface not active
|
||||
add interface=ether3
|
||||
/ip dhcp-server alert
|
||||
add disabled=no interface=494 on-alert=rogue-dhcp valid-server=\
|
||||
DC:2C:6E:DD:87:58
|
||||
/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
|
||||
add address=10.10.160.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.175.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.160.0/20 dns-server=204.110.191.240,204.110.191.250 \
|
||||
domain=vntx.net gateway=100.64.175.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/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
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether2-climax
|
||||
add action=accept chain=forward comment=\
|
||||
|
|
@ -502,12 +516,12 @@ set propagate-ttl=no
|
|||
/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=\
|
||||
add address=204.110.191.248 secret=dyhhtcUft3CJtDfYFG1S6 service=ppp \
|
||||
src-address=204.110.188.94 timeout=2s
|
||||
add address=204.110.191.2 secret=dyhhtcUft3CJtDfYFG1S6 service=ppp \
|
||||
src-address=204.110.188.94 timeout=2s
|
||||
add accounting-backup=yes address=45.76.56.5 disabled=yes secret=\
|
||||
dyhhtcUft3CJtDfYFG1S6 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 \
|
||||
|
|
@ -529,12 +543,11 @@ add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1A00::/44 || dst==2\
|
|||
606:1c80:0:10::111/128 || (dst-len==64 && dst==2606:1c80:0:17::/64)) { acc\
|
||||
ept; } else { reject; }"
|
||||
/routing ospf interface-template
|
||||
add area=ospf-area-1 auth=sha512 auth-id=1 disabled=no interfaces=\
|
||||
ether2-climax type=ptp use-bfd=no
|
||||
add area=ospf-area-1 disabled=no passive
|
||||
add area=backbone-v2 cost=10 interfaces=ether2-climax priority=1 type=ptp \
|
||||
use-bfd=no
|
||||
add area=backbone-v2 passive
|
||||
/routing ospf static-neighbor
|
||||
add address=10.250.1.70%ether2-climax area=ospf-area-1 disabled=no \
|
||||
poll-interval=10s
|
||||
add address=10.250.1.70%ether2-climax area=*1 disabled=no poll-interval=10s
|
||||
/snmp
|
||||
set contact=graham@vntx.net enabled=yes location="33.208204, -96.462530"
|
||||
/system clock
|
||||
|
|
@ -559,3 +572,7 @@ set auto-upgrade=yes
|
|||
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
|
||||
/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!\""
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# 2026-05-14 13:40:53 by RouterOS 7.21.4
|
||||
# 2026-07-10 10:54:21 by RouterOS 7.21.4
|
||||
# software id = FUVS-HCM5
|
||||
#
|
||||
# model = CCR1009-7G-1C-1S+
|
||||
|
|
@ -117,16 +117,18 @@ add address-pool=mgmt interface=mgmt lease-script="{\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" lease-time=10m name=mgmt
|
||||
\n" lease-time=1h name=mgmt
|
||||
/ip smb users
|
||||
set [ find default=yes ] disabled=yes
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=982-cust-pd-1 prefix=2606:1c80:1301::/48 prefix-length=56
|
||||
/ppp profile
|
||||
add dhcpv6-pd-pool=982-cust-pd-1 local-address=100.64.63.253 name=982 \
|
||||
on-down="{\
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
add change-tcp-mss=yes dhcpv6-pd-pool=982-cust-pd-1 dns-server=\
|
||||
204.110.191.240,204.110.191.250 idle-timeout=1h 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\"\
|
||||
|
|
@ -234,7 +236,9 @@ add dhcpv6-pd-pool=982-cust-pd-1 local-address=100.64.63.253 name=982 \
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" remote-address=cgnat remote-ipv6-prefix-pool=982-cust-pd-1
|
||||
\n" only-one=yes remote-address=cgnat remote-ipv6-prefix-pool=\
|
||||
982-cust-pd-1
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/queue type
|
||||
add kind=fq-codel name=fq-codel
|
||||
/queue interface
|
||||
|
|
@ -290,16 +294,13 @@ 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
|
||||
# ipv6 *accept router advertisements* configuration has changed, please restart device to apply settings
|
||||
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
|
||||
# ipv6 *accept router advertisements* configuration has changed, please restart device to apply settings
|
||||
set tcp-syncookies=yes
|
||||
/ipv6 settings
|
||||
# ipv6 *accept router advertisements* configuration has changed, please restart device to apply settings
|
||||
set accept-router-advertisements=no
|
||||
/interface pppoe-server server
|
||||
add authentication=mschap2 default-profile=982 disabled=no interface=982 \
|
||||
|
|
@ -311,6 +312,9 @@ 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 alert
|
||||
add disabled=no interface=mgmt on-alert=rogue-dhcp valid-server=\
|
||||
DC:2C:6E:66:50:BF
|
||||
/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
|
||||
|
|
@ -320,12 +324,14 @@ 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
|
||||
add address=10.10.48.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.63.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.28.0/22 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=100.64.31.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/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
|
||||
|
|
@ -369,9 +375,17 @@ 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
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether7-380
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (in)" in-interface=ether7-380
|
||||
add action=fasttrack-connection chain=forward comment=\
|
||||
|
|
@ -446,15 +460,14 @@ add interface=ether7-380
|
|||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/ppp aaa
|
||||
set use-radius=yes
|
||||
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.126 timeout=300ms
|
||||
add address=204.110.191.2 disabled=yes require-message-auth=no service=ppp \
|
||||
add address=204.110.191.248 secret=wj61jc2gitzeomx6 service=ppp src-address=\
|
||||
204.110.188.126 timeout=2s
|
||||
add address=204.110.191.2 disabled=yes secret=wj61jc2gitzeomx6 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
|
||||
add accounting-backup=yes address=45.76.56.5 disabled=yes secret=\
|
||||
wj61jc2gitzeomx6 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 bgp connection
|
||||
|
|
@ -470,8 +483,8 @@ add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1300::/44 || dst==2\
|
|||
606:1c80:0:10::110/128 || (dst-len==64 && dst==2606:1c80:0:14::/64)) { acc\
|
||||
ept; } else { reject; }"
|
||||
/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 auth-id=1 auth-key="" 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
|
||||
/snmp
|
||||
set contact=graham@vntx.net enabled=yes location="33.148902, -96.495811"
|
||||
|
|
@ -490,9 +503,12 @@ 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
|
||||
/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!\""
|
||||
|
|
|
|||
4
mikrotik-tool/add-gaiia-user.rsc
Normal file
4
mikrotik-tool/add-gaiia-user.rsc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Add gaiia user with full access to all MikroTik routers
|
||||
# First try to update existing user, then add if it doesn't exist
|
||||
/user set [find name=gaiia] password=ordQnwVQWyUAnLMTbJgyk0xH6Z group=full
|
||||
/user add name=gaiia password=ordQnwVQWyUAnLMTbJgyk0xH6Z group=full
|
||||
3
mikrotik-tool/bfd-fix-core.rsc
Normal file
3
mikrotik-tool/bfd-fix-core.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/routing ospf interface-template set numbers=*D use-bfd=no
|
||||
/routing ospf interface-template set numbers=*8 use-bfd=no
|
||||
/routing ospf interface-template set numbers=*7 use-bfd=no
|
||||
2
mikrotik-tool/bfd-fix-culleoka.rsc
Normal file
2
mikrotik-tool/bfd-fix-culleoka.rsc
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/routing ospf interface-template set numbers=*6 use-bfd=no
|
||||
/routing ospf interface-template set numbers=*7 use-bfd=no
|
||||
1
mikrotik-tool/bfd-fix-lowry.rsc
Normal file
1
mikrotik-tool/bfd-fix-lowry.rsc
Normal file
|
|
@ -0,0 +1 @@
|
|||
/routing ospf interface-template set numbers=*2 use-bfd=no
|
||||
3
mikrotik-tool/bfd-fix-newhope.rsc
Normal file
3
mikrotik-tool/bfd-fix-newhope.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/routing ospf interface-template set numbers=*2 use-bfd=no
|
||||
/routing ospf interface-template set numbers=*6 use-bfd=no
|
||||
/routing ospf interface-template set numbers=*E use-bfd=no
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# 2026-05-14 13:40:52 by RouterOS 7.21.4
|
||||
# 2026-07-10 10:54:21 by RouterOS 7.21.4
|
||||
# software id = UETF-WF31
|
||||
#
|
||||
# model = CCR2004-16G-2S+
|
||||
|
|
@ -41,7 +41,7 @@ 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=cgnat interface=climax-bridge lease-time=1h 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\
|
||||
|
|
@ -132,15 +132,16 @@ add address-pool=climax-mgmt interface=mgmt lease-script="{\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" name=climax-mgmt
|
||||
\n" lease-time=1h name=climax-mgmt
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=climax-cust-pd-1 prefix=2606:1c80:1101::/48 prefix-length=56
|
||||
/ppp profile
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
add bridge-learning=no change-tcp-mss=yes dhcpv6-pd-pool=climax-cust-pd-1 \
|
||||
dns-server=204.110.191.240,204.110.191.20 local-address=cgnat name=pppoe \
|
||||
on-down="{\
|
||||
dns-server=204.110.191.240,204.110.191.250 idle-timeout=1h 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\"\
|
||||
|
|
@ -248,8 +249,10 @@ add bridge-learning=no change-tcp-mss=yes dhcpv6-pd-pool=climax-cust-pd-1 \
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" remote-address=cgnat remote-ipv6-prefix-pool=climax-cust-pd-1 \
|
||||
use-compression=no use-encryption=no use-ipv6=no use-mpls=no use-upnp=no
|
||||
\n" only-one=yes remote-address=cgnat remote-ipv6-prefix-pool=\
|
||||
climax-cust-pd-1 use-compression=no use-encryption=no use-ipv6=no \
|
||||
use-mpls=no use-upnp=no
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/queue type
|
||||
add kind=fq-codel name=fq-codel
|
||||
/queue interface
|
||||
|
|
@ -296,7 +299,6 @@ add bridge=climax-bridge ingress-filtering=no interface=ether8-michael \
|
|||
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 \
|
||||
|
|
@ -310,7 +312,7 @@ set max-neighbor-entries=8192 tcp-syncookies=yes
|
|||
/ipv6 settings
|
||||
set accept-router-advertisements=no
|
||||
/interface pppoe-server server
|
||||
add authentication=chap,mschap2 default-profile=pppoe disabled=no interface=\
|
||||
add authentication=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
|
||||
|
|
@ -324,17 +326,33 @@ 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 alert
|
||||
add disabled=no interface=climax-bridge on-alert=rogue-dhcp valid-server=\
|
||||
F4:1E:57:6B:41:C1
|
||||
/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
|
||||
add address=10.0.102.0/24 dns-server=204.110.191.240,204.110.191.250 gateway=\
|
||||
10.0.102.254 ntp-server=23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=10.10.16.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.31.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.4.0/22 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=100.64.7.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=204.110.188.32/27 dns-server=204.110.191.240,204.110.191.250 \
|
||||
domain=vntx.net gateway=204.110.188.62 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/ip firewall address-list
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether5-494
|
||||
add action=accept chain=forward comment=\
|
||||
|
|
@ -350,6 +368,11 @@ 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=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (in)" in-interface=ether3-culleoka-11ghz
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=\
|
||||
ether3-culleoka-11ghz
|
||||
add action=fasttrack-connection chain=forward comment=\
|
||||
"fasttrack established/related" connection-state=established,related
|
||||
add action=accept chain=forward comment="accept established/related" \
|
||||
|
|
@ -459,6 +482,7 @@ add advertise-dns=yes interface=climax-bridge other-configuration=yes
|
|||
add interface=ether6-verona-11ghz mpls-mtu=1508
|
||||
add interface=ether4-380-airfiber24 mpls-mtu=1508
|
||||
add interface=ether5-494 mpls-mtu=1508
|
||||
add interface=ether3-culleoka-11ghz mpls-mtu=1508
|
||||
/mpls ldp
|
||||
add disabled=no lsr-id=10.254.254.102 transport-addresses=10.254.254.102 vrf=\
|
||||
main
|
||||
|
|
@ -466,14 +490,15 @@ add disabled=no lsr-id=10.254.254.102 transport-addresses=10.254.254.102 vrf=\
|
|||
add interface=ether6-verona-11ghz
|
||||
add interface=ether4-380-airfiber24
|
||||
add interface=ether5-494
|
||||
add interface=ether3-culleoka-11ghz
|
||||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/ppp aaa
|
||||
set interim-update=1h use-radius=yes
|
||||
set interim-update=15m use-radius=yes
|
||||
/radius
|
||||
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||
add address=204.110.191.248 secret=ich7cp0j1qpe0801 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 \
|
||||
add address=204.110.191.2 secret=ich7cp0j1qpe0801 service=ppp,hotspot,dhcp \
|
||||
src-address=204.110.188.62 timeout=2s
|
||||
/radius incoming
|
||||
set accept=yes
|
||||
|
|
@ -494,12 +519,14 @@ add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1100::/44 || dst==2\
|
|||
==2606:1c80:0:17::/64 || dst==2606:1c80:0:20::/64 || dst==2606:1c80:0:21::\
|
||||
/64))) { accept; } else { reject; }"
|
||||
/routing ospf interface-template
|
||||
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=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
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether6-verona-11ghz priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 cost=10 disabled=no interfaces=ether5-494 priority=1 \
|
||||
type=ptp use-bfd=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet 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
|
||||
|
|
@ -522,3 +549,7 @@ add address=0.us.pool.ntp.org
|
|||
set channel=long-term
|
||||
/system routerboard settings
|
||||
set auto-upgrade=yes enter-setup-on=delete-key
|
||||
/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!\""
|
||||
|
|
|
|||
1
mikrotik-tool/core-ssh-preseem-fix.rsc
Normal file
1
mikrotik-tool/core-ssh-preseem-fix.rsc
Normal file
|
|
@ -0,0 +1 @@
|
|||
/ip firewall connection tracking set tcp-established-timeout=1d
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
# 2026-05-14 13:40:53 by RouterOS 7.21.4
|
||||
# software id = XS5B-41QR
|
||||
# 2026-07-10 10:54:21 by RouterOS 7.21.4
|
||||
# software id = QL96-4NKM
|
||||
#
|
||||
# model = CCR1009-7G-1C-1S+
|
||||
# serial number = 8495073BCE3B
|
||||
# model = CCR2004-16G-2S+
|
||||
# serial number = HMC0B6HX8XX
|
||||
/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 \
|
||||
|
|
@ -18,16 +16,16 @@ 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 \
|
||||
set [ find default-name=ether7 ] l2mtu=9000 name=ether7-380tower \
|
||||
rx-flow-control=auto tx-flow-control=auto
|
||||
set [ find default-name=ether8 ] l2mtu=9000 name=ether8-380-lan \
|
||||
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
|
||||
add interface=ether8-380-lan name=vlan10_ether8 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
|
||||
|
|
@ -36,7 +34,7 @@ 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="{\
|
||||
add address-pool=380 interface=ether8-380-lan 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\"\
|
||||
|
|
@ -127,7 +125,7 @@ add address-pool=380 interface=combo1-380 lease-script="{\
|
|||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" lease-time=1h name=380
|
||||
add address-pool=380-mgmt interface=vlan10_combo1 lease-script="{\
|
||||
add address-pool=380-mgmt interface=vlan10_ether8 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\"\
|
||||
|
|
@ -221,13 +219,14 @@ add address-pool=380-mgmt interface=vlan10_combo1 lease-script="{\
|
|||
/ip smb users
|
||||
set [ find default=yes ] disabled=yes
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=core-cust-pd-1 prefix=2606:1c80:1401::/48 prefix-length=56
|
||||
/ppp profile
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
add change-tcp-mss=yes dhcpv6-pd-pool=core-cust-pd-1 dns-server=\
|
||||
204.110.191.240,204.110.191.20 local-address=100.64.11.253 name=380 \
|
||||
on-down="{\
|
||||
204.110.191.240,204.110.191.250 idle-timeout=1h 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\"\
|
||||
|
|
@ -335,13 +334,13 @@ add change-tcp-mss=yes dhcpv6-pd-pool=core-cust-pd-1 dns-server=\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" remote-address=380 remote-ipv6-prefix-pool=core-cust-pd-1 use-ipv6=no \
|
||||
use-upnp=no
|
||||
set *FFFFFFFE local-address=172.16.91.254 remote-address=sstp
|
||||
\n" only-one=yes remote-address=380 remote-ipv6-prefix-pool=\
|
||||
core-cust-pd-1 use-ipv6=no use-upnp=no
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250 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
|
||||
|
|
@ -349,10 +348,11 @@ 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 ether8-380-lan queue=FQ_Codel
|
||||
set sfp-sfpplus1-edge-preseem queue=FQ_Codel
|
||||
/routing bgp instance
|
||||
add as=393837 cluster-id=10.254.254.253 name=bgp-instance-1 router-id=\
|
||||
10.254.254.253
|
||||
add as=393837 cluster-id=10.254.254.253 disabled=no name=bgp-instance-1 \
|
||||
router-id=10.254.254.253
|
||||
/routing bgp template
|
||||
set default as=65530 disabled=no
|
||||
/routing id
|
||||
|
|
@ -362,6 +362,8 @@ 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
|
||||
/routing ospf area
|
||||
add disabled=no instance=default-v2 name=backbone-v2
|
||||
/routing rip instance
|
||||
add disabled=no name=rip-instance-1
|
||||
/routing table
|
||||
add fib name=testnat
|
||||
/snmp community
|
||||
|
|
@ -383,9 +385,8 @@ set accept-router-advertisements=no 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
|
||||
ether8-380-lan max-mru=1492 max-mtu=1492 one-session-per-host=yes \
|
||||
service-name=380
|
||||
/ip address
|
||||
add address=204.110.191.185/30 interface=sfp-sfpplus1-edge-preseem network=\
|
||||
204.110.191.184
|
||||
|
|
@ -400,18 +401,36 @@ 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=\
|
||||
add address=10.250.1.246/29 disabled=yes interface=ether8-380-lan 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
|
||||
add address=100.64.11.254/22 interface=ether8-380-lan network=100.64.8.0
|
||||
add address=10.10.79.254/20 interface=vlan10_ether8 network=10.10.64.0
|
||||
/ip dhcp-server alert
|
||||
add disabled=no interface=ether8-380-lan on-alert=rogue-dhcp valid-server=\
|
||||
D0:EA:11:77:4E:5D
|
||||
/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
|
||||
add address=10.10.64.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.79.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.8.0/22 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=100.64.11.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/ip firewall address-list
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether1-982-60ghz
|
||||
add action=accept chain=forward comment=\
|
||||
|
|
@ -441,8 +460,8 @@ add action=accept chain=forward comment=\
|
|||
sfp-sfpplus1-edge-preseem
|
||||
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=drop chain=forward src-address-list=suspended
|
||||
add action=drop chain=forward dst-address-list=suspended
|
||||
add action=accept chain=forward comment="accept established/related" \
|
||||
connection-state=established,related
|
||||
/ip ipsec profile
|
||||
|
|
@ -457,25 +476,29 @@ 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=\
|
||||
add check-gateway=ping disabled=yes 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 \
|
||||
add disabled=yes distance=1 dst-address=10.250.1.88/29 gateway=10.250.1.94 \
|
||||
routing-table=main scope=30 target-scope=10
|
||||
add disabled=yes dst-address=10.254.254.101/32 gateway=10.250.1.94
|
||||
add disabled=yes dst-address=10.254.254.102/32 gateway=10.250.1.94
|
||||
add disabled=yes dst-address=10.250.1.64/29 gateway=10.250.1.94
|
||||
add disabled=yes distance=1 dst-address=10.250.1.24/29 gateway=10.250.1.94 \
|
||||
routing-table=main scope=30 target-scope=10
|
||||
add disabled=yes distance=1 dst-address=10.250.1.8/29 gateway=10.250.1.94 \
|
||||
routing-table=main scope=30 target-scope=10
|
||||
add disabled=yes distance=1 dst-address=10.10.16.0/20 gateway=10.250.1.94 \
|
||||
routing-table=main scope=30 target-scope=10
|
||||
add disabled=yes distance=1 dst-address=10.10.0.0/20 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 disabled=yes 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
|
||||
|
|
@ -507,9 +530,9 @@ add comment="lowry loopback (via newhope)" distance=1 dst-address=\
|
|||
/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 ssh address=204.110.188.0/22,10.0.0.0/8,0.0.0.0/0 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 winbox address=0.0.0.0/0
|
||||
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
|
||||
|
|
@ -530,13 +553,13 @@ add address=2606:1c80:0:14::1 advertise=no comment="P2P core<->982 60GHz" \
|
|||
interface=ether1-982-60ghz
|
||||
add address=2606:1c80:0:15::1 advertise=no comment="P2P core<->culleoka" \
|
||||
interface=ether6-culleoka-11ghz
|
||||
add address=2606:1c80:1400::1 comment="380 mgmt LAN" interface=vlan10_combo1
|
||||
add address=2606:1c80:1400::1 comment="380 mgmt LAN" interface=vlan10_ether8
|
||||
add address=2606:1c80:1400:1::1 comment="380 customer LAN (PPPoE+DHCP)" \
|
||||
interface=combo1-380
|
||||
interface=ether8-380-lan
|
||||
/ipv6 dhcp-server
|
||||
add dhcp-option=v6-dns interface=vlan10_combo1 name=core-mgmt-stateless
|
||||
add address-pool=core-cust-pd-1 dhcp-option=v6-dns interface=combo1-380 name=\
|
||||
core-cust-pd-server
|
||||
add dhcp-option=v6-dns interface=vlan10_ether8 name=core-mgmt-stateless
|
||||
add address-pool=core-cust-pd-1 dhcp-option=v6-dns interface=ether8-380-lan \
|
||||
name=core-cust-pd-server
|
||||
/ipv6 firewall filter
|
||||
add action=accept chain=input comment=established connection-state=\
|
||||
established,related
|
||||
|
|
@ -556,8 +579,8 @@ add action=accept chain=forward comment="v6 outbound (all vntx sources)" \
|
|||
add action=drop chain=forward comment="default deny"
|
||||
/ipv6 nd
|
||||
set [ find default=yes ] advertise-dns=yes
|
||||
add advertise-dns=yes interface=vlan10_combo1 other-configuration=yes
|
||||
add advertise-dns=yes interface=combo1-380 other-configuration=yes
|
||||
add advertise-dns=yes interface=vlan10_ether8 other-configuration=yes
|
||||
add advertise-dns=yes interface=ether8-380-lan other-configuration=yes
|
||||
/mpls interface
|
||||
add interface=ether5-climax mpls-mtu=1508
|
||||
add interface=ether6-culleoka-11ghz mpls-mtu=1508
|
||||
|
|
@ -576,14 +599,10 @@ add interface=ether1-982-60ghz
|
|||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/ppp aaa
|
||||
set use-radius=yes
|
||||
set interim-update=15m 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
|
||||
add address=204.110.191.248 secret=TpYBHmrHd8vRelg service=ppp src-address=\
|
||||
204.110.191.185 timeout=2s
|
||||
/routing bfd configuration
|
||||
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
|
||||
/routing bgp connection
|
||||
|
|
@ -640,27 +659,34 @@ add chain=v6-rr-out disabled=no rule="if (dst==::/0 || dst-len==44 || dst-len=\
|
|||
=64 || dst-len==128) { accept; } else { reject; }"
|
||||
add chain=v6-rr-in disabled=no rule="if (dst==::/0 || dst-len==44 || dst-len==\
|
||||
64 || dst-len==128) { accept; } else { reject; }"
|
||||
/routing ospf area range
|
||||
add area=backbone-v2 disabled=no prefix=::/0
|
||||
/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=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||
ether4-newhope priority=1 type=ptp use-bfd=no
|
||||
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 \
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether6-culleoka-11ghz priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether4-newhope priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 auth-id=1 cost=10 disabled=yes 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=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether5-climax priority=1 type=ptp use-bfd=no
|
||||
/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 interface-template
|
||||
add disabled=no instance=rip-instance-1
|
||||
/routing rip static-neighbor
|
||||
add address="" disabled=no instance=*1
|
||||
add address="" disabled=no instance=rip-instance-1
|
||||
/routing rule
|
||||
add action=lookup-only-in-table disabled=yes src-address=10.10.0.0/16 table=\
|
||||
testnat
|
||||
|
|
@ -688,11 +714,17 @@ add address=216.229.4.66
|
|||
add address=1.us.pool.ntp.org
|
||||
/system package update
|
||||
set channel=long-term
|
||||
/system routerboard settings
|
||||
set auto-upgrade=yes enter-setup-on=delete-key
|
||||
/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
|
||||
/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 graphing interface
|
||||
add
|
||||
/tool graphing queue
|
||||
|
|
|
|||
75
mikrotik-tool/culleoka-opt82-hotspot.rsc
Normal file
75
mikrotik-tool/culleoka-opt82-hotspot.rsc
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# On the DHCP server "culleoka" (ether2-netonix), update the lease script
|
||||
# to add/remove hotspot bypass entries based on Option 82 presence.
|
||||
# Devices WITH Option 82 → bypassed (internet access)
|
||||
# Devices WITHOUT Option 82 → fall through to 0.0.0.0/0 type=blocked
|
||||
|
||||
/ip dhcp-server set lease-script="{\
|
||||
\n:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/production/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/cdc24944-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 # Deassign: remove hotspot bypass for this IP\
|
||||
\n /ip hotspot ip-binding remove [find address=\$leaseActIP];\
|
||||
\n\
|
||||
\n :do {\
|
||||
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\"}\"\
|
||||
\n :set success1 1;\
|
||||
\n :log info \"DHCP deassignment sent to iptrack for \$leaseActMAC / \$leaseActIP\";\
|
||||
\n } on-error={\
|
||||
\n :log error \"DHCP FAILED deassignment iptrack attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP\";\
|
||||
\n }\
|
||||
\n\
|
||||
\n :do {\
|
||||
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\\\":\\\"\\\"}\"\
|
||||
\n :set success2 1;\
|
||||
\n :log info \"DHCP deassignment sent to gaiia for \$leaseActMAC / \$leaseActIP\";\
|
||||
\n } on-error={\
|
||||
\n :log error \"DHCP FAILED deassignment gaiia 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=\$leaseActIP] agent-remote-id];\
|
||||
\n\
|
||||
\n # If Option 82 remote ID is present, bypass hotspot for this IP\
|
||||
\n :if (\$remoteID != \"\") do={\
|
||||
\n /ip hotspot ip-binding add address=\$leaseActIP mac-address=\$leaseActMAC server=hotspot1 to-address=\$leaseActIP type=bypassed;\
|
||||
\n :log info \"DHCP Option 82 present for \$leaseActMAC / \$leaseActIP (remoteID=\$remoteID) - hotspot bypassed\";\
|
||||
\n } else={\
|
||||
\n :log warning \"DHCP NO Option 82 for \$leaseActMAC / \$leaseActIP - staying blocked by hotspot\";\
|
||||
\n }\
|
||||
\n\
|
||||
\n :do {\
|
||||
\n /tool fetch duration=30s mode=https url=\"\$url2\" http-method=post http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\\\":\\\"\$remoteID\\\"}\"\
|
||||
\n :set success1 1;\
|
||||
\n :log info \"DHCP assignment sent to iptrack for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||
\n } on-error={\
|
||||
\n :log error \"DHCP FAILED assignment iptrack attempt \$attempts/\$max for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||
\n }\
|
||||
\n\
|
||||
\n :do {\
|
||||
\n /tool fetch duration=30s mode=https url=\"\$url\" http-method=post http-header-field=\"Content-Type: application/json\" http-data=\"{\\\"bound\\\":\\\"\$leaseBound\\\",\\\"mac\\\":\\\"\$leaseActMAC\\\",\\\"ip\\\":\\\"\$leaseActIP\\\",\\\"server\\\":\\\"\$leaseServerName\\\",\\\"remoteId\\\":\\\"\$remoteID\\\"}\"\
|
||||
\n :set success2 1;\
|
||||
\n :log info \"DHCP assignment sent to gaiia for \$leaseActMAC / \$leaseActIP / \$remoteID\";\
|
||||
\n } on-error={\
|
||||
\n :log error \"DHCP FAILED assignment gaiia attempt \$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}" [find name=culleoka]
|
||||
24
mikrotik-tool/culleoka-opt82-poll.rsc
Normal file
24
mikrotik-tool/culleoka-opt82-poll.rsc
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/system scheduler remove [find name=opt82-hotspot-sync]
|
||||
/system script remove [find name=opt82-hotspot-sync]
|
||||
:delay 1s
|
||||
/system script add name=opt82-hotspot-sync owner=admin policy=read,write,test source={
|
||||
# Add bypass for any bound lease with Option 82
|
||||
/ip dhcp-server lease foreach={
|
||||
:if ($activeAgentRemoteId != "" && $status = "bound") do={
|
||||
:if ([/ip hotspot ip-binding find where address=$activeAddress server=hotspot1 mac-address=$activeMacAddress] = "") do={
|
||||
/ip hotspot ip-binding add address=$activeAddress mac-address=$activeMacAddress server=hotspot1 to-address=$activeAddress type=bypassed
|
||||
:log info "opt82-poll: bypassed $activeMacAddress / $activeAddress"
|
||||
}
|
||||
}
|
||||
}
|
||||
# Remove bypasses for IPs that no longer have any bound lease
|
||||
/ip hotspot ip-binding foreach={
|
||||
:if ($server = "hotspot1" && $mac-address != "") do={
|
||||
:if ([/ip dhcp-server lease find where activeAddress=$address] = "") do={
|
||||
/ip hotspot ip-binding remove $.
|
||||
:log info "opt82-poll: removed bypass for $mac-address / $address (no lease)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/system scheduler add name=opt82-hotspot-sync interval=10s on-event="/system script run opt82-hotspot-sync" policy=read,write,test
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
# 2026-05-14 13:40:53 by RouterOS 7.21.4
|
||||
** WARNING: connection is not using a post-quantum key exchange algorithm.
|
||||
** This session may be vulnerable to "store now, decrypt later" attacks.
|
||||
** The server may need to be upgraded. See https://openssh.com/pq.html
|
||||
# 2026-07-10 17:44:20 by RouterOS 7.21.5
|
||||
# software id = HVP9-3G0K
|
||||
#
|
||||
# model = CCR1009-7G-1C-1S+
|
||||
|
|
@ -41,10 +44,11 @@ set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
|||
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
|
||||
mac-auth-mode=mac-as-username-and-password name=hsprof1 \
|
||||
radius-accounting=no use-radius=yes
|
||||
/ip hotspot
|
||||
add addresses-per-mac=unlimited idle-timeout=none interface=ether2-netonix \
|
||||
name=hotspot1 profile=hsprof1
|
||||
add addresses-per-mac=unlimited disabled=no 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]" \
|
||||
|
|
@ -149,7 +153,7 @@ add address-pool=cpe interface=mgmt lease-script="{\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" lease-time=1h name=cpe use-radius=accounting
|
||||
\n" lease-time=1h name=cpe
|
||||
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\
|
||||
|
|
@ -208,21 +212,24 @@ add address-pool=culleoka-tower interface=culleoka-tower lease-script="{\
|
|||
\n\
|
||||
\n}\
|
||||
\n" lease-time=1h name=culleoka-tower
|
||||
add address-pool=clayton disabled=yes interface=vlan_30_clayton lease-time=\
|
||||
10m name=clayton
|
||||
add address-pool=clayton disabled=yes interface=vlan_30_clayton lease-time=1h \
|
||||
name=clayton
|
||||
/ip smb users
|
||||
set [ find default=yes ] disabled=yes
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=culleoka-cust-pd-1 prefix=2606:1c80:1601::/48 prefix-length=56
|
||||
/ppp profile
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
add change-tcp-mss=yes dhcpv6-pd-pool=culleoka-cust-pd-1 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\"\
|
||||
204.110.191.240,204.110.191.250 idle-timeout=1h local-address=\
|
||||
100.64.27.253 name=pppoe on-down="{\
|
||||
\n#:local url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/pro\
|
||||
duction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0\
|
||||
a7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||
\n:local url \"https://workflows.gaiia.systems/tenant_eHH8oyd82GgaXstfRhHW\
|
||||
Di/workflow_38tqPV3f6PF3dVJHe22KVR\"\
|
||||
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||
\n:local max 1\
|
||||
\n\
|
||||
|
|
@ -274,9 +281,11 @@ add change-tcp-mss=yes dhcpv6-pd-pool=culleoka-cust-pd-1 dns-server=\
|
|||
\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 url \"https://xtjlpnubrg.execute-api.us-east-1.amazonaws.com/pro\
|
||||
duction/on-start-workflow-execution/6f19a48f-04f7-40c1-a4e0-8cb66df99213/0\
|
||||
a7f4443-fc8a-4fe0-807c-f535d2aa1865\"\
|
||||
\n:local url \"https://workflows.gaiia.systems/tenant_eHH8oyd82GgaXstfRhHW\
|
||||
Di/workflow_38tqPV3f6PF3dVJHe22KVR\"\
|
||||
\n:local url2 \"https://iptrack.vntx.net/api/pppoe\"\
|
||||
\n:local max 5\
|
||||
\n\
|
||||
|
|
@ -327,9 +336,10 @@ add change-tcp-mss=yes dhcpv6-pd-pool=culleoka-cust-pd-1 dns-server=\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" only-one=no remote-address=culleoka-cgnat remote-ipv6-prefix-pool=\
|
||||
\n" only-one=yes remote-address=culleoka-cgnat remote-ipv6-prefix-pool=\
|
||||
culleoka-cust-pd-1 use-compression=no use-encryption=no use-ipv6=no \
|
||||
use-mpls=no use-upnp=no
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/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=""
|
||||
|
|
@ -384,22 +394,29 @@ set tcp-syncookies=yes
|
|||
/ipv6 settings
|
||||
set accept-router-advertisements=no
|
||||
/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
|
||||
add accept-empty-service=no authentication=mschap2 default-profile=pppoe \
|
||||
disabled=no interface=ether2-netonix max-mtu=1492 one-session-per-host=\
|
||||
yes service-name=culleoka
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
vlan_30_clayton max-mtu=1492 one-session-per-host=yes service-name=\
|
||||
clayton
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
ether5-jeff-tv max-mtu=1492 one-session-per-host=yes service-name=jeff-tv
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
vlan100_netonix8 max-mtu=1492 one-session-per-host=yes service-name=\
|
||||
service1
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
vlan101_netonix9 max-mtu=1492 one-session-per-host=yes service-name=\
|
||||
service2
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
vlan102_netonix10 max-mtu=1492 one-session-per-host=yes service-name=\
|
||||
service3
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
vlan103_netonix13 max-mtu=1492 one-session-per-host=yes service-name=\
|
||||
service4
|
||||
add authentication=mschap2 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
|
||||
|
|
@ -504,10 +521,10 @@ add add-arp=yes address-pool=culleoka-cgnat dhcp-option-set=vntx interface=\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" lease-time=1h name=culleoka use-radius=accounting
|
||||
\n" lease-time=1h name=culleoka
|
||||
/ip dhcp-server alert
|
||||
add disabled=no interface=culleoka on-alert=rogue-dhcp valid-server=\
|
||||
64:D1:54:D3:E1:50
|
||||
add disabled=no interface=ether2-netonix on-alert=rogue-dhcp valid-server=\
|
||||
64:D1:54:D3:E1:53
|
||||
/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
|
||||
|
|
@ -523,34 +540,56 @@ 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
|
||||
add address=10.0.104.0/24 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.0.104.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=10.10.96.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.111.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.24.0/22 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=100.64.27.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.96.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=100.64.111.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=204.110.188.128/27 dns-server=204.110.191.240,204.110.191.250 \
|
||||
domain=vntx.net gateway=204.110.188.158 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dhcp-server option sets
|
||||
add name=vntx options=*1
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/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
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=passthrough chain=unused-hs-chain comment=\
|
||||
"place hotspot rules here" disabled=yes
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
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=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (in)" in-interface=ether1-climax-11ghz
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether1-climax-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 firewall nat
|
||||
add action=passthrough chain=unused-hs-chain comment=\
|
||||
"place hotspot rules here" disabled=yes
|
||||
/ip hotspot ip-binding
|
||||
add address=100.64.27.97 type=bypassed
|
||||
add address=100.64.25.4 type=bypassed
|
||||
|
|
@ -641,23 +680,25 @@ add advertise-dns=yes interface=mgmt other-configuration=yes
|
|||
add interface=mgmt prefix=2606:1c80:1600::/64
|
||||
/mpls interface
|
||||
add interface=ether6-380-11ghz mpls-mtu=1508
|
||||
add interface=ether1-climax-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
|
||||
add interface=ether1-climax-11ghz
|
||||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/ppp aaa
|
||||
set interim-update=1h use-radius=yes
|
||||
set interim-update=15m use-radius=yes
|
||||
/radius
|
||||
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||
add address=204.110.191.248 secret=x6ov8lwph4kxp0d7 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 \
|
||||
add address=204.110.191.2 secret=x6ov8lwph4kxp0d7 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
|
||||
add accounting-backup=yes address=45.76.56.5 disabled=yes secret=\
|
||||
x6ov8lwph4kxp0d7 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
|
||||
|
|
@ -673,10 +714,12 @@ add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1600::/44 || dst==2\
|
|||
606:1c80:0:10::104/128 || (dst-len==64 && (dst==2606:1c80:0:15::/64 || dst\
|
||||
==2606:1c80:0:21::/64))) { accept; } else { reject; }"
|
||||
/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-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=20 disabled=no \
|
||||
interfaces=ether1-climax-11ghz priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether6-380-11ghz priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 disabled=no passive
|
||||
/routing ospf static-neighbor
|
||||
add address=10.250.1.14%ether1-climax-11ghz area=backbone-v2 comment=climax \
|
||||
|
|
@ -720,6 +763,7 @@ 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=\
|
||||
|
|
@ -735,3 +779,5 @@ add dont-require-permissions=no name=rogue-dhcp owner=admin policy=\
|
|||
":log warning message=\"Rogue DHCP server detected!\""
|
||||
/tool bandwidth-server
|
||||
set enabled=no
|
||||
/tool romon
|
||||
set secrets=vntx1830
|
||||
|
|
|
|||
3
mikrotik-tool/dhcp-1h-494.rsc
Normal file
3
mikrotik-tool/dhcp-1h-494.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=dhcp1]
|
||||
/ip dhcp-server set lease-time=1h [find name=dhcp2]
|
||||
2
mikrotik-tool/dhcp-1h-982.rsc
Normal file
2
mikrotik-tool/dhcp-1h-982.rsc
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=mgmt]
|
||||
3
mikrotik-tool/dhcp-1h-climax.rsc
Normal file
3
mikrotik-tool/dhcp-1h-climax.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=dhcp1]
|
||||
/ip dhcp-server set lease-time=1h [find name=climax-mgmt]
|
||||
3
mikrotik-tool/dhcp-1h-core.rsc
Normal file
3
mikrotik-tool/dhcp-1h-core.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=380]
|
||||
/ip dhcp-server set lease-time=1h [find name=380-mgmt]
|
||||
5
mikrotik-tool/dhcp-1h-culleoka.rsc
Normal file
5
mikrotik-tool/dhcp-1h-culleoka.rsc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=culleoka]
|
||||
/ip dhcp-server set lease-time=1h [find name=cpe]
|
||||
/ip dhcp-server set lease-time=1h [find name=culleoka-tower]
|
||||
/ip dhcp-server set lease-time=1h [find name=clayton]
|
||||
3
mikrotik-tool/dhcp-1h-lowry.rsc
Normal file
3
mikrotik-tool/dhcp-1h-lowry.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=dhcp1]
|
||||
/ip dhcp-server set lease-time=1h [find name=mgmt]
|
||||
4
mikrotik-tool/dhcp-1h-newhope.rsc
Normal file
4
mikrotik-tool/dhcp-1h-newhope.rsc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=newhope]
|
||||
/ip dhcp-server set lease-time=1h [find name=management]
|
||||
/ip dhcp-server set lease-time=1h [find name=newhope-tower]
|
||||
5
mikrotik-tool/dhcp-1h-verona.rsc
Normal file
5
mikrotik-tool/dhcp-1h-verona.rsc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# set all DHCP lease times to 1h
|
||||
/ip dhcp-server set lease-time=1h [find name=verona-cpe]
|
||||
/ip dhcp-server set lease-time=1h [find name=altoga-cpe]
|
||||
/ip dhcp-server set lease-time=1h [find name=verona-tower]
|
||||
/ip dhcp-server set lease-time=1h [find name=verona]
|
||||
1
mikrotik-tool/dhcp-set-server-all.rsc
Normal file
1
mikrotik-tool/dhcp-set-server-all.rsc
Normal file
|
|
@ -0,0 +1 @@
|
|||
/ip dhcp-server lease set [find where dynamic=no] server=all
|
||||
1
mikrotik-tool/dhcp-use-radius-no.rsc
Normal file
1
mikrotik-tool/dhcp-use-radius-no.rsc
Normal file
|
|
@ -0,0 +1 @@
|
|||
/ip dhcp-server set use-radius=no [find]
|
||||
5
mikrotik-tool/diag.rsc
Normal file
5
mikrotik-tool/diag.rsc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/routing ospf neighbor print
|
||||
/interface print
|
||||
/routing ospf interface-template print
|
||||
/routing ospf interface print
|
||||
/ip address print
|
||||
3
mikrotik-tool/dns-local-resolvers.rsc
Normal file
3
mikrotik-tool/dns-local-resolvers.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/ip dns set servers=204.110.191.240,204.110.191.250
|
||||
/ip dhcp-server network set [find] dns-server=204.110.191.240,204.110.191.250
|
||||
/ppp profile set [find] dns-server=204.110.191.240,204.110.191.250
|
||||
6
mikrotik-tool/dns-quad9.rsc
Normal file
6
mikrotik-tool/dns-quad9.rsc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Set fleet-wide DNS to Quad9 (9.9.9.9 and 149.112.112.112)
|
||||
# Applies to: /ip dns, all DHCP networks, all PPPoE profiles
|
||||
|
||||
/ip dns set servers=9.9.9.9,149.112.112.112
|
||||
/ip dhcp-server network set [find] dns-server=9.9.9.9,149.112.112.112
|
||||
/ppp profile set [find] dns-server=9.9.9.9,149.112.112.112
|
||||
3
mikrotik-tool/dns-update-edge.rsc
Normal file
3
mikrotik-tool/dns-update-edge.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/ppp profile set [find] dns-server=204.110.191.240,204.110.191.250
|
||||
/ip dhcp-server network set [find] dns-server=204.110.191.240,204.110.191.250
|
||||
/ip dns set servers=204.110.191.240,204.110.191.250
|
||||
2
mikrotik-tool/dns-update.rsc
Normal file
2
mikrotik-tool/dns-update.rsc
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/ppp profile set [find] dns-server=204.110.191.240,204.110.191.250
|
||||
/ip dhcp-server network set [find] dns-server=204.110.191.240,204.110.191.250
|
||||
16
mikrotik-tool/edge-block-winbox.rsc
Normal file
16
mikrotik-tool/edge-block-winbox.rsc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Block incoming winbox from non-trusted IPs
|
||||
# Run: ./mikrotik-tool script edge edge-block-winbox.rsc
|
||||
|
||||
# Add missing RFC 1918 private ranges to trusted list
|
||||
/ip firewall address-list
|
||||
add address=172.16.0.0/12 list=trusted comment="RFC 1918 private"
|
||||
add address=192.168.0.0/16 list=trusted comment="RFC 1918 private"
|
||||
|
||||
# Restrict winbox service to trusted networks only
|
||||
/ip service
|
||||
set winbox address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
|
||||
|
||||
# Firewall drop for winbox from non-trusted sources (belt and suspenders)
|
||||
# Place before "Established Input" to catch new connection attempts early
|
||||
/ip firewall filter
|
||||
add chain=input action=drop dst-port=8291 protocol=tcp src-address-list=!trusted comment="block winbox from non-trusted" place-before="Established Input"
|
||||
1
mikrotik-tool/edge-ssh-preseem-fix.rsc
Normal file
1
mikrotik-tool/edge-ssh-preseem-fix.rsc
Normal file
|
|
@ -0,0 +1 @@
|
|||
/ip firewall connection tracking set tcp-established-timeout=1d
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# may/14/2026 13:40:52 by RouterOS 6.49.18
|
||||
# jul/10/2026 10:54:22 by RouterOS 6.49.18
|
||||
# software id = 8XZE-R7EJ
|
||||
#
|
||||
# model = CCR2004-1G-12S+2XS
|
||||
|
|
@ -31,7 +31,9 @@ add name=servers-public ranges=204.110.191.193-204.110.191.217
|
|||
add address-pool=380building disabled=no interface=sfp-sfpplus8-server-switch \
|
||||
name=380-building
|
||||
/ppp profile
|
||||
add name=RWB_sstp_profile
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
add dns-server=204.110.191.240,204.110.191.250 name=RWB_sstp_profile
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/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 \
|
||||
|
|
@ -205,6 +207,8 @@ 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
|
||||
add address=192.168.0.5/24 interface=sfp-sfpplus8-server-switch network=\
|
||||
192.168.0.0
|
||||
/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
|
||||
|
|
@ -219,10 +223,10 @@ add address=10.0.0.252 client-id=1:bc:24:11:f5:81:d6 mac-address=\
|
|||
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
|
||||
add address=10.0.0.0/24 dns-server=204.110.191.240,204.110.191.250 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 \
|
||||
gateway=204.110.191.254
|
||||
/ip dns
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/ip firewall address-list
|
||||
|
|
@ -267,6 +271,8 @@ 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
|
||||
add address=172.16.0.0/12 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" 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
|
||||
|
|
@ -277,6 +283,10 @@ add action=accept chain=forward comment="BGP Forward Reply" protocol=tcp \
|
|||
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=drop chain=input comment="block winbox from non-trusted" dst-port=\
|
||||
8291 protocol=tcp src-address-list=!trusted
|
||||
add action=drop chain=input comment="block winbox from non-trusted" dst-port=\
|
||||
8291 protocol=tcp src-address-list=!trusted
|
||||
add action=accept chain=input comment="Established Input" connection-state=\
|
||||
established,related
|
||||
add action=accept chain=forward comment="Established Forward" \
|
||||
|
|
@ -530,6 +540,8 @@ 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 winbox address=\
|
||||
204.110.188.0/22,10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
|
||||
set api-ssl address=0.0.0.0/0 certificate=server
|
||||
/ip ssh
|
||||
set always-allow-password-login=yes forwarding-enabled=remote strong-crypto=\
|
||||
|
|
|
|||
3
mikrotik-tool/fix-ospf.rsc
Normal file
3
mikrotik-tool/fix-ospf.rsc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/routing ospf interface-template set [find where interfaces=ether4-newhope] auth=sha512 authentication-key=5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet use-bfd=no
|
||||
/routing ospf interface-template set [find where interfaces=ether6-culleoka-11ghz] auth=sha512 authentication-key=5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet use-bfd=no
|
||||
/routing ospf interface-template add area=backbone-v2 auth=sha512 auth-id=1 authentication-key=5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no interfaces=ether5-climax priority=1 type=ptp use-bfd=no
|
||||
38
mikrotik-tool/home-recursive-failover.rsc
Normal file
38
mikrotik-tool/home-recursive-failover.rsc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# home-recursive-failover.rsc
|
||||
# Replace stateful netwatch enable/disable failover with stateless recursive
|
||||
# check-gateway failover. Root cause of the "VNTX default stuck disabled"
|
||||
# incident: netwatch down-script persists disabled=yes (survives reboots),
|
||||
# and its probe to 4.2.2.2 is only glued to the VNTX path while the probe-pin
|
||||
# route is active — so the check can die permanently (verona hotspot-binding
|
||||
# loss) or leak out another WAN (TMO netwatch reads "up" today with the TMO
|
||||
# interface physically down, answered via VNTX).
|
||||
#
|
||||
# New model (standard ROS recursive failover):
|
||||
# - probe pin: 4.2.2.x/32 -> WAN gw %interface, scope=10, NO check-gateway.
|
||||
# Stays active whenever the interface has link, so probes always egress
|
||||
# the WAN under test regardless of any default-route state.
|
||||
# - default: 0.0.0.0/0 gw=4.2.2.x target-scope=11 check-gateway=ping.
|
||||
# check-gateway pings 4.2.2.x THROUGH the pin; 2 misses (~20s) -> route
|
||||
# inactive (not disabled), first success -> active again. Nothing latches.
|
||||
# - Detection is 10s-cadence/2-miss instead of netwatch's 2s/1s single
|
||||
# packet — deliberate: the AF11 backbone has documented >1s RF bursts
|
||||
# (same reason BFD was turned off fleet-wide 2026-05-09).
|
||||
|
||||
/ip route
|
||||
# pins: remove check-gateway (the check belongs on the recursive default)
|
||||
set [find comment="TMO probe pin"] check-gateway=none
|
||||
set [find comment="VNTX probe pin"] check-gateway=none
|
||||
set [find comment="Starlink probe pin"] check-gateway=none
|
||||
# defaults: recurse through the probe IP, carry the check
|
||||
set [find comment="Default via TMO (primary)"] gateway=4.2.2.1 check-gateway=ping
|
||||
set [find comment="Default via VNTX (secondary)"] gateway=4.2.2.2 check-gateway=ping
|
||||
# Starlink default already gateway=4.2.2.3 + check-gateway=ping (correct form)
|
||||
# tmo table default (eweka policy routing) already recurses via 4.2.2.1;
|
||||
# add the check so it goes inactive (falls back to main) when TMO upstream dies
|
||||
set [find comment="tmo table default"] check-gateway=ping
|
||||
|
||||
# netwatch scripts are the latch — remove them
|
||||
/tool netwatch
|
||||
remove [find comment="TMO path"]
|
||||
remove [find comment="VNTX path"]
|
||||
remove [find comment="Starlink path"]
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# 2026-05-14 13:40:52 by RouterOS 7.22.3
|
||||
# 2026-07-17 08:45:20 by RouterOS 7.23.2
|
||||
# software id = ZGNY-ZJW7
|
||||
#
|
||||
# model = RB5009UG+S+
|
||||
|
|
@ -9,7 +9,6 @@ add admin-mac=74:4D:28:1A:67:0A auto-mac=no comment=defconf mtu=1500 name=\
|
|||
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
|
||||
|
|
@ -20,12 +19,14 @@ 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
|
||||
/container
|
||||
add envlists=tailscale interface=veth1 layer-dir="" logging=yes name=\
|
||||
tailscale-mikrotik:latest remote-image=\
|
||||
fluent-networks/tailscale-mikrotik:latest root-dir=\
|
||||
/disk1/containers/tailscale start-on-boot=yes workdir=/
|
||||
/interface list
|
||||
add comment=defconf name=WAN
|
||||
add comment=defconf name=LAN
|
||||
|
|
@ -40,12 +41,11 @@ add add-arp=yes address-pool=home bootp-lease-time=lease-time bootp-support=\
|
|||
add address-pool=dhcp_pool1 interface=ether3-servers name=servers
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:4700:4700::1111''2606:4700:4700::1001'"
|
||||
/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
|
||||
/ppp profile
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/queue type
|
||||
set 0 kind=fq-codel
|
||||
/routing table
|
||||
|
|
@ -55,8 +55,9 @@ add comment="vntx v6 /56 egress via verona" disabled=no fib name=v6-verona
|
|||
/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=::/0 authentication-password=testtest authentication-protocol=\
|
||||
SHA1 encryption-password=testtest 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=\
|
||||
|
|
@ -72,11 +73,33 @@ add dont-require-permissions=no name=api-ssl-certgen owner=admin policy=\
|
|||
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="" logging=yes name=\
|
||||
tailscale-mikrotik:latest remote-image=\
|
||||
fluent-networks/tailscale-mikrotik:latest root-dir=\
|
||||
/disk1/containers/tailscale start-on-boot=yes workdir=/
|
||||
/zerotier
|
||||
set zt1 identity="a5f13ab687:0:487e3dd9982223e1aa0b13752a061609180dd3926b46be2\
|
||||
7527a299db6fb1959bc79f486a0e8e70a50a1c0c81c5048ced502f97a4db2cac167551339d\
|
||||
137d3c2:8620c195d88a8ccd49c6264419b9bfcb9af6456cb1c0a35c83f7ed3396375fe446\
|
||||
e18897162866ebcadb374304f379a5ab006e4f0c0e3bb59438fccfcccef0c1"
|
||||
/app
|
||||
set HA-otbr-matter required-hw-devices=ttyACM0:usb1:default:/dev/ttyACM0
|
||||
set cinny firewall-redirects=8094:80:tcp:web
|
||||
set goaway container-command-lines=goaway:none:docker.io/pommee/goaway:latest
|
||||
set home-assistant container-command-lines=\
|
||||
home-assistant:none:lscr.io/linuxserver/homeassistant
|
||||
set lorawan-stack secrets="lorawan-stack__admin_password:="
|
||||
set n8n firewall-redirects=5678:5678:tcp:web
|
||||
set nextcloud container-command-lines="db:none:docker.io/postgres:17,redis:non\
|
||||
e:docker.io/valkey/valkey:/bin/sh -c 'valkey-server --port 6379 --appendon\
|
||||
ly yes --requirepass \$VALKEY_PASSWORD',server:none:docker.io/nextcloud:ap\
|
||||
ache"
|
||||
set otbr required-hw-devices=ttyACM0:usb1:default:/dev/ttyACM0
|
||||
set pihole environment="pihole:FTLCONF_dns_listeningMode=all,pihole:FTLCONF_we\
|
||||
bserver_api_password=password"
|
||||
set redlib firewall-redirects=8087:8080:tcp:web
|
||||
set solr container-command-lines=solr:none:docker.io/solr:latest
|
||||
set uptime-kuma container-command-lines=\
|
||||
uptime-kuma:none:docker.io/louislam/uptime-kuma:1
|
||||
set zulip secrets="zulip__postgres_password:=,zulip__memcached_password:=,zuli\
|
||||
p__rabbitmq_password:=,zulip__redis_password:=,zulip__secret_key:=,zulip__\
|
||||
email_password:="
|
||||
/container config
|
||||
set registry-url=https://ghcr.io tmpdir=/disk1/pull
|
||||
/container envs
|
||||
|
|
@ -122,16 +145,16 @@ add address=204.110.191.1/27 interface=ether5-vntx-static network=\
|
|||
add address=10.0.19.254/22 interface=bridge network=10.0.16.0
|
||||
add address=10.0.15.254/21 interface=ether3-servers network=10.0.8.0
|
||||
/ip dhcp-client
|
||||
# Interface not active
|
||||
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=\
|
||||
|
|
@ -167,20 +190,18 @@ add address=10.0.15.253 client-id=1:78:9a:18:3f:cb:fe mac-address=\
|
|||
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=\
|
||||
add address=10.0.16.11 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=\
|
||||
add address=10.0.16.14 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=\
|
||||
add address=10.0.16.15 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.16.13 mac-address=EC:94:CB:AA:56:A3 server=server1
|
||||
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
|
||||
|
|
@ -191,12 +212,21 @@ add address=10.0.15.30 mac-address=94:C6:91:A4:19:80 server=servers
|
|||
add address=10.0.15.31 client-id=\
|
||||
ff:a:12:17:11:0:1:0:1:31:8f:72:ff:7c:d3:a:12:17:11 mac-address=\
|
||||
7C:D3:0A:12:17:11 server=servers
|
||||
add address=10.0.16.10 mac-address=40:F5:20:C5:C7:5E server=server1
|
||||
add address=10.0.16.12 client-id=1:40:4c:ca:69:9:6c mac-address=\
|
||||
40:4C:CA:69:09:6C server=server1
|
||||
add address=10.0.16.6 client-id=1:e8:f6:a:e0:c4:4 mac-address=\
|
||||
E8:F6:0A:E0:C4:04 server=server1
|
||||
add address=10.0.15.25 mac-address=BC:24:11:FB:42:B0 server=servers
|
||||
add address=10.0.19.253 client-id=1:b8:69:f4:9f:b7:12 mac-address=\
|
||||
B8:69:F4:9F:B7:12 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 \
|
||||
add address=10.0.8.0/21 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
mcintire.me gateway=10.0.15.254
|
||||
add address=10.0.16.0/22 dns-server=1.1.1.1,204.110.191.250 domain=w5isp.com \
|
||||
gateway=10.0.19.254
|
||||
/ip dns
|
||||
set servers=9.9.9.9,149.112.112.112
|
||||
set servers=9.9.9.9,204.110.191.250
|
||||
/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=\
|
||||
|
|
@ -279,7 +309,15 @@ 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
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
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=\
|
||||
|
|
@ -388,7 +426,7 @@ add action=dst-nat chain=dstnat disabled=yes dst-address=204.110.191.1 \
|
|||
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
|
||||
add action=masquerade chain=srcnat disabled=yes out-interface=ether7-starlink
|
||||
/ip proxy
|
||||
set port=8198 src-address=10.0.19.254
|
||||
/ip route
|
||||
|
|
@ -420,27 +458,25 @@ 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 comment="Default via TMO (primary)" disabled=no distance=1 dst-address=\
|
||||
0.0.0.0/0 gateway=192.168.12.1 target-scope=11
|
||||
add comment="Default via VNTX (secondary)" disabled=no distance=2 \
|
||||
dst-address=0.0.0.0/0 gateway=204.110.191.30 target-scope=11
|
||||
add check-gateway=ping comment="Default via TMO (primary)" disabled=no \
|
||||
distance=1 dst-address=0.0.0.0/0 gateway=4.2.2.1 target-scope=11
|
||||
add check-gateway=ping comment="Default via VNTX (secondary)" disabled=no \
|
||||
distance=2 dst-address=0.0.0.0/0 gateway=4.2.2.2 target-scope=11
|
||||
add check-gateway=ping comment="Default via Starlink (last\
|
||||
\n resort)" distance=3 dst-address=0.0.0.0/0 gateway=4.2.2.3 \
|
||||
target-scope=11
|
||||
add comment="tmo table default" disabled=no dst-address=0.0.0.0/0 gateway=\
|
||||
4.2.2.1 routing-table=tmo
|
||||
add check-gateway=ping comment="TMO probe pin" distance=1 dst-address=\
|
||||
\n resort)" disabled=yes distance=3 dst-address=0.0.0.0/0 gateway=\
|
||||
4.2.2.3 target-scope=11
|
||||
add check-gateway=ping comment="tmo table default" disabled=no dst-address=\
|
||||
0.0.0.0/0 gateway=4.2.2.1 routing-table=tmo
|
||||
add check-gateway=none comment="TMO probe pin" distance=1 dst-address=\
|
||||
4.2.2.1/32 gateway=192.168.12.1%ether6-tmobile scope=10
|
||||
add check-gateway=ping comment="VNTX probe pin" distance=1 dst-address=\
|
||||
add check-gateway=none comment="VNTX probe pin" distance=1 dst-address=\
|
||||
4.2.2.2/32 gateway=204.110.191.30%ether5-vntx-static scope=10
|
||||
add check-gateway=ping comment="Starlink probe pin" distance=1 dst-address=\
|
||||
4.2.2.3/32 gateway=192.168.1.1%ether7-starlink scope=10
|
||||
add disabled=no distance=1 dst-address=192.168.100.0/24 gateway=\
|
||||
add check-gateway=none comment="Starlink probe pin" disabled=yes distance=1 \
|
||||
dst-address=4.2.2.3/32 gateway=192.168.1.1%ether7-starlink scope=10
|
||||
add disabled=yes distance=1 dst-address=192.168.100.0/24 gateway=\
|
||||
ether7-starlink routing-table=main scope=30 target-scope=10
|
||||
/ip service
|
||||
set ftp disabled=yes
|
||||
|
|
@ -526,17 +562,3 @@ add allow-address=10.0.16.0/24
|
|||
set allowed-interface-list=LAN
|
||||
/tool mac-server mac-winbox
|
||||
set allowed-interface-list=LAN
|
||||
/tool netwatch
|
||||
add comment="TMO path" down-script="/ip route disable [find comment=\"Default \
|
||||
via TMO (primary)\"]; /ip route disable [find comment=\"tmo table default\
|
||||
\"]" host=4.2.2.1 interval=2s timeout=1s type=simple up-script="/ip route \
|
||||
enable [find comment=\"Default via TMO (primary)\"]; /ip route enable [fin\
|
||||
d comment=\"tmo table default\"]"
|
||||
add comment="VNTX path" down-script=\
|
||||
"/ip route disable [find comment=\"Default via VNTX (secondary)\"]" host=\
|
||||
4.2.2.2 interval=2s timeout=1s type=simple up-script=\
|
||||
"/ip route enable [find comment=\"Default via VNTX (secondary)\"]"
|
||||
add comment="Starlink path" down-script=\
|
||||
"/ip route disable [find comment=\"Default via Starlink (last resort)\"]" \
|
||||
host=4.2.2.3 interval=2s timeout=1s type=simple up-script=\
|
||||
"/ip route enable [find comment=\"Default via Starlink (last resort)\"]"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# 2026-05-14 13:40:53 by RouterOS 7.21.4
|
||||
# 2026-07-10 10:54:21 by RouterOS 7.21.4
|
||||
# software id = 2I9X-PQZP
|
||||
#
|
||||
# model = CCR1009-7G-1C-1S+
|
||||
|
|
@ -35,8 +35,7 @@ add name=video_http regexp="http/(0\\.9|1\\.0|1\\.1)[\\x20][1-5][0-9][0-9].*[\
|
|||
\\x09-\\x0d].*[\\x09-\\x0d]content-type:.video/"
|
||||
/ip hotspot profile
|
||||
add dns-name=lowrycrossing.vntx.net hotspot-address=100.64.23.254 login-by=\
|
||||
mac,http-chap mac-auth-mode=mac-as-username-and-password name=hsprof1 \
|
||||
radius-interim-update=1h use-radius=yes
|
||||
mac,http-chap mac-auth-mode=mac-as-username-and-password name=hsprof1
|
||||
/ip hotspot
|
||||
add idle-timeout=none interface=lowrycrossing name=hotspot1 profile=hsprof1
|
||||
/ip hotspot user profile
|
||||
|
|
@ -144,13 +143,14 @@ add address-pool=mgmt interface=management lease-script="{\
|
|||
/ip smb users
|
||||
set [ find default=yes ] disabled=yes
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=lowry-cust-pd-1 prefix=2606:1c80:1901::/48 prefix-length=56
|
||||
/ppp profile
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250
|
||||
add change-tcp-mss=yes dhcpv6-pd-pool=lowry-cust-pd-1 dns-server=\
|
||||
204.110.191.20,204.110.191.240 local-address=100.64.159.254 name=pppoe \
|
||||
on-down="{\
|
||||
204.110.191.240,204.110.191.250 idle-timeout=1h local-address=\
|
||||
100.64.159.254 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\"\
|
||||
|
|
@ -261,6 +261,7 @@ add change-tcp-mss=yes dhcpv6-pd-pool=lowry-cust-pd-1 dns-server=\
|
|||
\n" only-one=yes remote-address=cgnat remote-ipv6-prefix-pool=\
|
||||
lowry-cust-pd-1 use-compression=no use-encryption=no use-ipv6=no \
|
||||
use-upnp=no
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/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 \
|
||||
|
|
@ -374,8 +375,9 @@ set tcp-syncookies=yes
|
|||
/ipv6 settings
|
||||
set accept-router-advertisements=no
|
||||
/interface pppoe-server server
|
||||
add default-profile=pppoe disabled=no interface=lowrycrossing max-mtu=1492 \
|
||||
mrru=1600 one-session-per-host=yes service-name=lowrycrossing
|
||||
add authentication=mschap2 default-profile=pppoe disabled=no interface=\
|
||||
lowrycrossing max-mtu=1492 one-session-per-host=yes service-name=\
|
||||
lowrycrossing
|
||||
/interface sstp-server server
|
||||
set certificate=vntx.net.pem_0
|
||||
/ip address
|
||||
|
|
@ -487,6 +489,9 @@ add add-arp=yes address-pool=cgnat dhcp-option-set=vntx interface=\
|
|||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" lease-time=1h name=dhcp1
|
||||
/ip dhcp-server alert
|
||||
add disabled=no interface=lowrycrossing on-alert=rogue-dhcp valid-server=\
|
||||
64:D1:54:D3:E2:1F
|
||||
/ip dhcp-server lease
|
||||
add address=10.10.159.13 mac-address=58:C1:7A:75:4D:66
|
||||
add address=10.10.159.11 mac-address=00:04:56:C4:FE:9D
|
||||
|
|
@ -494,16 +499,19 @@ add address=10.10.144.34 mac-address=00:04:56:60:49:43
|
|||
add address=10.10.159.12 mac-address=58:C1:7A:71:A7:A8
|
||||
add address=10.10.159.10 mac-address=00:04:56:D7:62:F6
|
||||
/ip dhcp-server network
|
||||
add address=10.10.144.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||
vntx.net gateway=10.10.159.254 ntp-server=204.110.191.19
|
||||
add address=100.64.144.0/20 dns-server=204.110.191.240,204.110.191.20 domain=\
|
||||
vntx.net gateway=100.64.159.254 ntp-server=204.110.191.19
|
||||
add address=204.110.188.192/27 dns-server=204.110.191.240,204.110.191.20 \
|
||||
domain=vntx.net gateway=204.110.188.222 ntp-server=204.110.191.19
|
||||
add address=10.10.144.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.159.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.144.0/20 dns-server=204.110.191.240,204.110.191.250 \
|
||||
domain=vntx.net gateway=100.64.159.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=204.110.188.192/27 dns-server=204.110.191.240,204.110.191.250 \
|
||||
domain=vntx.net gateway=204.110.188.222 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dhcp-server option sets
|
||||
add name=vntx options=*1
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/ip firewall address-list
|
||||
add address=204.110.191.229 list=whitelist
|
||||
add address=portal.vntx.net list=whitelist
|
||||
|
|
@ -1222,7 +1230,15 @@ add address=100.64.23.25 comment="Abbie Andrews (1081)" list=Active
|
|||
add address=100.64.23.12 comment="Nhu Morrison (2111)" list=\
|
||||
ResidentialAdvanced
|
||||
add address=100.64.23.12 comment="Nhu Morrison (2111)" list=Active
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether1-newhope
|
||||
add action=accept chain=forward comment=\
|
||||
|
|
@ -1241,7 +1257,7 @@ add address=10.100.0.144-10.100.158.254
|
|||
add address=10.100.159.0/24 type=bypassed
|
||||
add address=0.0.0.0/0 type=blocked
|
||||
/ip hotspot user
|
||||
add name=admin
|
||||
add name=admin password=h8xd9tkryg
|
||||
/ip hotspot walled-garden
|
||||
add comment="place hotspot rules here" disabled=yes
|
||||
/ip hotspot walled-garden ip
|
||||
|
|
@ -1320,13 +1336,13 @@ add interface=ether1-newhope
|
|||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/ppp aaa
|
||||
set interim-update=1h use-radius=yes
|
||||
set interim-update=15m use-radius=yes
|
||||
/radius
|
||||
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||
add address=204.110.191.248 secret=260oy5od2x2ltubh service=ppp,hotspot,dhcp \
|
||||
src-address=204.110.188.222 timeout=3s
|
||||
add address=204.110.191.2 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||
add address=204.110.191.2 secret=260oy5od2x2ltubh service=ppp,hotspot,dhcp \
|
||||
src-address=204.110.188.222 timeout=3s
|
||||
add accounting-backup=yes address=45.76.56.5 require-message-auth=no service=\
|
||||
add accounting-backup=yes address=45.76.56.5 secret=260oy5od2x2ltubh service=\
|
||||
ppp,hotspot,dhcp src-address=204.110.188.222 timeout=3s
|
||||
/radius incoming
|
||||
set accept=yes
|
||||
|
|
@ -1345,8 +1361,9 @@ add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1900::/44 || dst==2\
|
|||
606:1c80:0:10::109/128 || (dst-len==64 && dst==2606:1c80:0:18::/64)) { acc\
|
||||
ept; } else { reject; }"
|
||||
/routing ospf interface-template
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||
ether1-newhope priority=1 type=ptp use-bfd=yes
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether1-newhope priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 disabled=no passive
|
||||
/snmp
|
||||
set contact=graham@vntx.net enabled=yes location="33.160873, -96.540479"
|
||||
|
|
@ -1417,5 +1434,7 @@ 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 e-mail
|
||||
set certificate-verification=no from=<LowryCrossing@vntx.net> server=\
|
||||
smtp.sendgrid.net tls=starttls user=veronanetworks
|
||||
set certificate-verification=no from=<LowryCrossing@vntx.net> password=\
|
||||
F9K2B2yhvE6YUnv server=smtp.sendgrid.net tls=starttls user=veronanetworks
|
||||
/tool romon
|
||||
set secrets=vntx1830
|
||||
|
|
|
|||
|
|
@ -404,13 +404,21 @@ func exportRouter(cfg *Config, r Router) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Printf("[%s] ssh %s:%d /export", r.Name, r.Host, sshPort)
|
||||
body, err := runOverSSH(r, sshPort, "/export")
|
||||
// Try show-sensitive first (ROS 7); fall back to plain export for ROS 6.
|
||||
cmd := "/export show-sensitive"
|
||||
log.Printf("[%s] ssh %s:%d %s", r.Name, r.Host, sshPort, cmd)
|
||||
body, err := runOverSSH(r, sshPort, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
log.Printf("[%s] show-sensitive failed (%v), falling back to /export", r.Name, err)
|
||||
cmd = "/export"
|
||||
log.Printf("[%s] ssh %s:%d %s", r.Name, r.Host, sshPort, cmd)
|
||||
body, err = runOverSSH(r, sshPort, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(body) == 0 {
|
||||
return fmt.Errorf("/export returned no output")
|
||||
return fmt.Errorf("%s returned no output", cmd)
|
||||
}
|
||||
|
||||
out := r.Name + ".rsc"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
# 2026-05-14 13:40:53 by RouterOS 7.21.4
|
||||
# 2026-07-10 10:54:21 by RouterOS 7.21.4
|
||||
# software id = 5HTF-YFWV
|
||||
#
|
||||
# model = CCR1009-7G-1C-1S+
|
||||
|
|
@ -34,8 +34,7 @@ set [ find default=yes ] ip-type=ipv4 use-network-apn=no
|
|||
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
|
||||
mac,http-chap mac-auth-mode=mac-as-username-and-password name=hsprof1
|
||||
/ip hotspot
|
||||
add addresses-per-mac=unlimited idle-timeout=none interface=\
|
||||
sfp-sfpplus1-edgepoint name=hotspot1 profile=hsprof1
|
||||
|
|
@ -151,14 +150,14 @@ add address-pool=dhcp_pool6 interface=ether7-tower lease-time=1h name=\
|
|||
/ip smb users
|
||||
set [ find default=yes ] disabled=yes
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
add code=23 name=v6-dns
|
||||
/ipv6 pool
|
||||
add name=newhope-cust-pd-1 prefix=2606:1c80:1801::/48 prefix-length=56
|
||||
/ppp profile
|
||||
set *0 remote-address=dhcp_pool3
|
||||
set *0 dns-server=204.110.191.240,204.110.191.250 remote-address=dhcp_pool3
|
||||
add change-tcp-mss=yes dhcpv6-pd-pool=newhope-cust-pd-1 dns-server=\
|
||||
204.110.191.240,204.110.191.20 local-address=100.64.19.253 name=newhope \
|
||||
on-down="{\
|
||||
204.110.191.240,204.110.191.250 idle-timeout=1h 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\"\
|
||||
|
|
@ -266,8 +265,9 @@ add change-tcp-mss=yes dhcpv6-pd-pool=newhope-cust-pd-1 dns-server=\
|
|||
\n }\
|
||||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" remote-address=cgnat remote-ipv6-prefix-pool=newhope-cust-pd-1 \
|
||||
use-upnp=no
|
||||
\n" only-one=yes remote-address=cgnat remote-ipv6-prefix-pool=\
|
||||
newhope-cust-pd-1 use-upnp=no
|
||||
set *FFFFFFFE dns-server=204.110.191.240,204.110.191.250
|
||||
/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 \
|
||||
|
|
@ -295,9 +295,11 @@ set default as=393837 disabled=no output.network=bgp-networks .redistribute=\
|
|||
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
|
||||
ospf-out redistribute=connected router-id=id-1
|
||||
/routing ospf area
|
||||
add disabled=no instance=default-v2 name=backbone-v2
|
||||
/routing rip instance
|
||||
add name=rip-instance-1
|
||||
/snmp community
|
||||
set [ find default=yes ] addresses=204.110.188.0/22,10.0.0.0/8 name=\
|
||||
kdyyJrT0Mm
|
||||
|
|
@ -314,16 +316,13 @@ add bridge=newhope ingress-filtering=no interface=combo1 internal-path-cost=\
|
|||
add bridge=newhope interface=ether5-switch
|
||||
add bridge=newhope interface=sfp-sfpplus1-edgepoint
|
||||
/ip firewall connection tracking
|
||||
# ipv6 *accept router advertisements* configuration has changed, please restart device to apply settings
|
||||
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
|
||||
# ipv6 *accept router advertisements* configuration has changed, please restart device to apply settings
|
||||
set tcp-syncookies=yes
|
||||
/ipv6 settings
|
||||
# ipv6 *accept router advertisements* configuration has changed, please restart device to apply settings
|
||||
set accept-router-advertisements=no
|
||||
/interface pppoe-server server
|
||||
add authentication=mschap2 default-profile=newhope disabled=no interface=\
|
||||
|
|
@ -439,25 +438,40 @@ add address-pool=cgnat dhcp-option-set=vntx interface=newhope lease-script="{\
|
|||
\n} while ( \$attempts < \$max )\
|
||||
\n}\
|
||||
\n" lease-time=1h name=newhope
|
||||
/ip dhcp-server alert
|
||||
add disabled=no interface=newhope on-alert=rogue-dhcp valid-server=\
|
||||
6C:3B:6B:E1:5D:46
|
||||
/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
|
||||
add address=10.0.108.0/24 dns-server=204.110.191.240,204.110.191.250 gateway=\
|
||||
10.0.108.254 ntp-server=23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=10.10.128.0/20 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=10.10.143.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.16.0/22 dns-server=204.110.191.240,204.110.191.250 domain=\
|
||||
vntx.net gateway=100.64.19.254 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=204.110.188.160/27 dns-server=204.110.191.240,204.110.191.250 \
|
||||
domain=vntx.net gateway=204.110.188.190 ntp-server=\
|
||||
23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dhcp-server option sets
|
||||
add name=vntx options=*1
|
||||
/ip dns
|
||||
set servers=9.9.9.9,1.1.1.1,2606:1c80::240,2606:1c80::250
|
||||
set servers=204.110.191.240,204.110.191.250
|
||||
/ip firewall address-list
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=\
|
||||
ether6-lowrycrossing
|
||||
|
|
@ -484,7 +498,7 @@ 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
|
||||
add name=admin password=h8xd9tkryg
|
||||
/ip hotspot walled-garden
|
||||
add comment="place hotspot rules here" disabled=yes
|
||||
add comment="place hotspot rules here" disabled=yes
|
||||
|
|
@ -580,13 +594,13 @@ add interface=ether6-lowrycrossing
|
|||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/ppp aaa
|
||||
set interim-update=1h use-radius=yes
|
||||
set interim-update=15m use-radius=yes
|
||||
/radius
|
||||
add address=204.110.191.248 require-message-auth=no service=ppp,hotspot,dhcp \
|
||||
add address=204.110.191.248 secret=ivcgfagb6f0t64ws 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 \
|
||||
add address=204.110.191.2 secret=ivcgfagb6f0t64ws 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=\
|
||||
add accounting-backup=yes address=45.76.56.5 secret=ivcgfagb6f0t64ws service=\
|
||||
ppp,hotspot,dhcp src-address=204.110.188.190 timeout=3s
|
||||
/radius incoming
|
||||
set accept=yes
|
||||
|
|
@ -607,15 +621,20 @@ add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1800::/44 || dst==2\
|
|||
606:1c80:0:10::108/128 || (dst-len==64 && (dst==2606:1c80:0:13::/64 || dst\
|
||||
==2606:1c80:0:18::/64))) { accept; } else { reject; }"
|
||||
/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-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether4 priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether6-lowrycrossing priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 auth-key=\
|
||||
5YHHWmoooAyVaFDX48ffjGjc36XMO5Irb7zS44Tsvet cost=10 disabled=no \
|
||||
interfaces=ether2-380 priority=1 type=ptp use-bfd=no
|
||||
add area=backbone-v2 disabled=no passive
|
||||
/routing rip interface-template
|
||||
add instance=rip-instance-1
|
||||
/routing rip static-neighbor
|
||||
add address="" disabled=no instance=*1
|
||||
add address="" disabled=no instance=rip-instance-1
|
||||
/snmp
|
||||
set contact=graham@vntx.net enabled=yes location="33.207391, -96.537840"
|
||||
/system clock
|
||||
|
|
@ -652,7 +671,6 @@ 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=\
|
||||
|
|
@ -685,11 +703,13 @@ 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
|
||||
set certificate-verification=no from=NewHope@vntx.net password=\
|
||||
F9K2B2yhvE6YUnv server=smtp.sendgrid.net tls=starttls user=veronanetworks
|
||||
/tool graphing interface
|
||||
add
|
||||
/tool graphing queue
|
||||
add
|
||||
/tool graphing resource
|
||||
add
|
||||
/tool romon
|
||||
set secrets=vntx1830
|
||||
|
|
|
|||
717
mikrotik-tool/newrouter.rsc
Normal file
717
mikrotik-tool/newrouter.rsc
Normal file
|
|
@ -0,0 +1,717 @@
|
|||
# Translated from core.rsc (CCR1009-7G-1C-1S+) for CCR2004-16G-2S+
|
||||
# Port mapping:
|
||||
# core combo1 → new ether8 (customer LAN: PPPoE+DHCP, mgmt vlan10)
|
||||
# core ether1..ether7 → new ether1..ether7 (unchanged)
|
||||
# core sfp-sfpplus1 → new sfp-sfpplus1 (edge via Preseem, unchanged)
|
||||
# new sfp-sfpplus2 → unused
|
||||
# new ether9..ether16 → unused
|
||||
/interface ethernet
|
||||
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=ether8 ] l2mtu=9000 name=ether8-380-lan \
|
||||
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=ether8-380-lan name=vlan10_ether8 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=ether8-380-lan 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_ether8 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
|
||||
/ipv6 dhcp-server option
|
||||
add code=23 name=v6-dns value="'2606:1c80::240''2606:1c80::250'"
|
||||
/ipv6 pool
|
||||
add name=core-cust-pd-1 prefix=2606:1c80:1401::/48 prefix-length=56
|
||||
/ppp profile
|
||||
set *0 dns-server=1.1.1.1,9.9.9.9
|
||||
add change-tcp-mss=yes dhcpv6-pd-pool=core-cust-pd-1 dns-server=\
|
||||
1.1.1.1,9.9.9.9 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 remote-ipv6-prefix-pool=core-cust-pd-1 use-ipv6=no \
|
||||
use-upnp=no
|
||||
set *FFFFFFFE dns-server=1.1.1.1,9.9.9.9 local-address=172.16.91.254 \
|
||||
remote-address=sstp
|
||||
/queue type
|
||||
add kind=fq-codel name=FQ_Codel
|
||||
/queue interface
|
||||
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 ether8-380-lan queue=FQ_Codel
|
||||
set sfp-sfpplus1-edge-preseem queue=FQ_Codel
|
||||
/routing bgp instance
|
||||
add as=393837 cluster-id=10.254.254.253 disabled=no 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
|
||||
/routing ospf area
|
||||
add disabled=no instance=default-v2 name=backbone-v2
|
||||
/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 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 accept-router-advertisements=no max-neighbor-entries=8192 \
|
||||
soft-max-neighbor-entries=8191
|
||||
/interface pppoe-server server
|
||||
add authentication=mschap2 default-profile=380 disabled=no interface=\
|
||||
ether8-380-lan 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=ether8-380-lan network=\
|
||||
10.250.1.240
|
||||
add address=100.64.11.254/22 interface=ether8-380-lan network=100.64.8.0
|
||||
add address=10.10.79.254/20 interface=vlan10_ether8 network=10.10.64.0
|
||||
/ip dhcp-server network
|
||||
add address=10.10.64.0/20 dns-server=1.1.1.1,9.9.9.9 domain=vntx.net gateway=\
|
||||
10.10.79.254 ntp-server=23.150.40.242,108.61.215.221,162.254.225.152
|
||||
add address=100.64.8.0/22 dns-server=1.1.1.1,9.9.9.9 domain=vntx.net gateway=\
|
||||
100.64.11.254 ntp-server=23.150.40.242,108.61.215.221,162.254.225.152
|
||||
/ip dns
|
||||
set servers=1.1.1.1,9.9.9.9
|
||||
/ip firewall address-list
|
||||
add address=204.110.188.0/22 comment="VNTX public IPs" list=trusted
|
||||
add address=100.64.0.0/10 comment="CGNAT pools" list=trusted
|
||||
add address=10.0.0.0/8 comment="RFC 1918 private" list=trusted
|
||||
add address=192.168.0.0/16 comment="RFC 1918 private" list=trusted
|
||||
/ip firewall filter
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=accept chain=input comment="allow trusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp src-address-list=trusted
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
add action=drop chain=input comment="drop untrusted to management services" \
|
||||
dst-port=8728-8729,8291,22 protocol=tcp
|
||||
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=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (in)" in-interface=ether3-edge-direct
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=ether3-edge-direct
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (in)" in-interface=\
|
||||
sfp-sfpplus1-edge-preseem
|
||||
add action=accept chain=forward comment=\
|
||||
"bypass fasttrack for MPLS spine (out)" out-interface=\
|
||||
sfp-sfpplus1-edge-preseem
|
||||
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=yes 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
|
||||
/ipv6 route
|
||||
add comment="default via preseem (primary)" distance=1 dst-address=::/0 \
|
||||
gateway=2606:1c80:0:1002::1
|
||||
add comment="default via direct (backup)" distance=2 dst-address=::/0 \
|
||||
gateway=2606:1c80:0:11::1
|
||||
add comment="edge loopback via preseem" distance=1 dst-address=\
|
||||
2606:1c80:0:10::254/128 gateway=2606:1c80:0:1002::1
|
||||
add comment="edge loopback via direct" distance=2 dst-address=\
|
||||
2606:1c80:0:10::254/128 gateway=2606:1c80:0:11::1
|
||||
add blackhole comment="core /44 aggregate (iBGP origin)" distance=200 \
|
||||
dst-address=2606:1c80:1400::/44
|
||||
add comment="verona loopback via climax" dst-address=2606:1c80:0:10::101/128 \
|
||||
gateway=2606:1c80:0:12::2
|
||||
add comment="climax loopback via climax P2P" dst-address=\
|
||||
2606:1c80:0:10::102/128 gateway=2606:1c80:0:12::2
|
||||
add comment="494 loopback (iBGP bootstrap, via climax)" distance=1 \
|
||||
dst-address=2606:1c80:0:10::111/128 gateway=2606:1c80:0:12::2
|
||||
add comment="982 loopback (iBGP bootstrap)" distance=1 dst-address=\
|
||||
2606:1c80:0:10::110/128 gateway=2606:1c80:0:14::2
|
||||
add comment="culleoka loopback (iBGP bootstrap)" distance=1 dst-address=\
|
||||
2606:1c80:0:10::104/128 gateway=2606:1c80:0:15::2
|
||||
add comment="newhope loopback (iBGP bootstrap)" distance=1 dst-address=\
|
||||
2606:1c80:0:10::108/128 gateway=2606:1c80:0:13::2
|
||||
add comment="lowry loopback (via newhope)" distance=1 dst-address=\
|
||||
2606:1c80:0:10::109/128 gateway=2606:1c80:0:13::2
|
||||
/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:10::253/128 advertise=no comment=loopback interface=\
|
||||
lo
|
||||
add address=2606:1c80:0:11::2 advertise=no comment=\
|
||||
"P2P core<->edge direct (backup)" interface=ether3-edge-direct
|
||||
add address=2606:1c80:0:1002::2 advertise=no comment=\
|
||||
"P2P core<->edge via preseem (primary)" interface=\
|
||||
sfp-sfpplus1-edge-preseem
|
||||
add address=2606:1c80:0:12::1 advertise=no comment="P2P core<->climax" \
|
||||
interface=ether5-climax
|
||||
add address=2606:1c80:0:13::1 advertise=no comment="P2P core<->newhope" \
|
||||
interface=ether4-newhope
|
||||
add address=2606:1c80:0:14::1 advertise=no comment="P2P core<->982 60GHz" \
|
||||
interface=ether1-982-60ghz
|
||||
add address=2606:1c80:0:15::1 advertise=no comment="P2P core<->culleoka" \
|
||||
interface=ether6-culleoka-11ghz
|
||||
add address=2606:1c80:1400::1 comment="380 mgmt LAN" interface=vlan10_ether8
|
||||
add address=2606:1c80:1400:1::1 comment="380 customer LAN (PPPoE+DHCP)" \
|
||||
interface=ether8-380-lan
|
||||
/ipv6 dhcp-server
|
||||
add dhcp-option=v6-dns interface=vlan10_ether8 name=core-mgmt-stateless
|
||||
add address-pool=core-cust-pd-1 dhcp-option=v6-dns interface=ether8-380-lan \
|
||||
name=core-cust-pd-server
|
||||
/ipv6 firewall filter
|
||||
add action=accept chain=input comment=established connection-state=\
|
||||
established,related
|
||||
add action=drop chain=input comment=invalid connection-state=invalid
|
||||
add action=accept chain=input comment=icmpv6 protocol=icmpv6
|
||||
add action=accept chain=input comment=link-local src-address=fe80::/10
|
||||
add action=accept chain=input comment=internal src-address=2606:1c80::/32
|
||||
add action=drop chain=input comment="default deny"
|
||||
add action=accept chain=forward comment=established connection-state=\
|
||||
established,related
|
||||
add action=drop chain=forward comment=invalid connection-state=invalid
|
||||
add action=accept chain=forward comment=PMTUD hop-limit=equal:1 protocol=\
|
||||
icmpv6
|
||||
add action=accept chain=forward comment=icmpv6 protocol=icmpv6
|
||||
add action=accept chain=forward comment="v6 outbound (all vntx sources)" \
|
||||
src-address=2606:1c80::/32
|
||||
add action=drop chain=forward comment="default deny"
|
||||
/ipv6 nd
|
||||
set [ find default=yes ] advertise-dns=yes
|
||||
add advertise-dns=yes interface=vlan10_ether8 other-configuration=yes
|
||||
add advertise-dns=yes interface=ether8-380-lan other-configuration=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
|
||||
add interface=ether3-edge-direct mpls-mtu=1508
|
||||
add interface=sfp-sfpplus1-edge-preseem 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
|
||||
/mpls settings
|
||||
set propagate-ttl=no
|
||||
/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 afi=ip,ipv6 as=393837 comment="iBGP to edge, v4 transport / v6 NLRI" \
|
||||
input.filter=v6-rr-in instance=bgp-instance-1 local.address=\
|
||||
2606:1c80:0:10::253 .role=ibgp-rr multihop=yes name=ibgp-rr-edge \
|
||||
nexthop-choice=default output.filter-chain=v6-rr-out .redistribute=\
|
||||
connected,static remote.address=2606:1c80:0:10::254 .as=393837 templates=\
|
||||
default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: climax" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-climax nexthop-choice=default \
|
||||
output.filter-chain=v6-rr-out .redistribute=connected,static \
|
||||
remote.address=2606:1c80:0:10::102 .as=393837 templates=default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: culleoka" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-culleoka nexthop-choice=default \
|
||||
output.filter-chain=v6-rr-out .redistribute=connected,static \
|
||||
remote.address=2606:1c80:0:10::104 .as=393837 templates=default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: newhope" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-newhope nexthop-choice=default \
|
||||
output.filter-chain=v6-rr-out .redistribute=connected,static \
|
||||
remote.address=2606:1c80:0:10::108 .as=393837 templates=default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: lowry" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-lowry nexthop-choice=default \
|
||||
output.filter-chain=v6-rr-out .redistribute=connected,static \
|
||||
remote.address=2606:1c80:0:10::109 .as=393837 templates=default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: 982" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-982 nexthop-choice=default output.filter-chain=\
|
||||
v6-rr-out .redistribute=connected,static remote.address=\
|
||||
2606:1c80:0:10::110 .as=393837 templates=default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: 494" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-494 nexthop-choice=default output.filter-chain=\
|
||||
v6-rr-out .redistribute=connected,static remote.address=\
|
||||
2606:1c80:0:10::111 .as=393837 templates=default
|
||||
add afi=ip,ipv6 as=393837 comment="RR client: verona" input.filter=v6-rr-in \
|
||||
instance=bgp-instance-1 local.address=2606:1c80:0:10::253 .role=ibgp-rr \
|
||||
multihop=yes name=ibgp-rr-verona nexthop-choice=default \
|
||||
output.filter-chain=v6-rr-out .redistribute=connected,static \
|
||||
remote.address=2606:1c80:0:10::101 .as=393837 templates=default
|
||||
/routing filter rule
|
||||
add chain=ospf-in disabled=no rule="accept;"
|
||||
add chain=ospf-out disabled=no rule="accept;"
|
||||
add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1400::/44 || dst==2\
|
||||
606:1c80:0:10::253/128 || (dst-len==64 && (dst==2606:1c80:0:11::/64 || dst\
|
||||
==2606:1c80:0:12::/64 || dst==2606:1c80:0:13::/64 || dst==2606:1c80:0:14::\
|
||||
/64 || dst==2606:1c80:0:15::/64 || dst==2606:1c80:0:1002::/64))) { accept;\
|
||||
\_} else { reject; }"
|
||||
add chain=v6-rr-out disabled=no rule="if (dst==::/0 || dst-len==44 || dst-len=\
|
||||
=64 || dst-len==128) { accept; } else { reject; }"
|
||||
add chain=v6-rr-in disabled=no rule="if (dst==::/0 || dst-len==44 || dst-len==\
|
||||
64 || dst-len==128) { accept; } else { reject; }"
|
||||
/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=no
|
||||
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
|
||||
ether4-newhope priority=1 type=ptp use-bfd=no
|
||||
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=no
|
||||
/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
|
||||
20
mikrotik-tool/opt82-sync.rsc
Normal file
20
mikrotik-tool/opt82-sync.rsc
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
:global opt82sync do={
|
||||
# Add bypass for any bound lease with Option 82
|
||||
/ip dhcp-server lease foreach={
|
||||
:if ($activeAgentRemoteId != "" && $status = "bound") do={
|
||||
:if ([/ip hotspot ip-binding find where address=$activeAddress server=hotspot1 mac-address=$activeMacAddress] = "") do={
|
||||
/ip hotspot ip-binding add address=$activeAddress mac-address=$activeMacAddress server=hotspot1 to-address=$activeAddress type=bypassed
|
||||
:log info "opt82-poll: bypassed $activeMacAddress / $activeAddress"
|
||||
}
|
||||
}
|
||||
}
|
||||
# Remove bypasses for IPs that no longer have any bound lease
|
||||
/ip hotspot ip-binding foreach={
|
||||
:if ($server = "hotspot1" && $mac-address != "") do={
|
||||
:if ([/ip dhcp-server lease find where activeAddress=$address] = "") do={
|
||||
/ip hotspot ip-binding remove $.
|
||||
:log info "opt82-poll: removed bypass for $mac-address / $address (no lease)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
mikrotik-tool/pppoe-fix-494.rsc
Normal file
18
mikrotik-tool/pppoe-fix-494.rsc
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Fix 5+6: Rebuild OSPF with standard naming + add redistribute=connected
|
||||
# Remove old OSPF config (templates first, then area, then instance)
|
||||
/routing ospf interface-template remove numbers=*5
|
||||
/routing ospf interface-template remove numbers=*4
|
||||
/routing ospf area remove numbers=*1
|
||||
/routing ospf instance remove numbers=*0
|
||||
# Recreate with standard naming and redistribute
|
||||
/routing ospf instance add name=default-v2 router-id=id-1 originate-default=never redistribute=connected in-filter-chain=ospf-in out-filter-chain=ospf-out version=2 vrf=main
|
||||
/routing ospf area add name=backbone-v2 area-id=0.0.0.0 instance=default-v2 type=default
|
||||
/routing ospf interface-template add area=backbone-v2 interfaces=ether2-climax cost=10 type=ptp use-bfd=no dead-interval=40s hello-interval=10s priority=1
|
||||
/routing ospf interface-template add area=backbone-v2 passive type=broadcast cost=1
|
||||
|
||||
# Fix 9: Add idle timeout to PPPoE profile
|
||||
/ppp profile set [find name="494"] idle-timeout=1h
|
||||
|
||||
# Fix 10: Increase RADIUS timeout from 300ms to 2s
|
||||
/radius set [find address=204.110.191.248] timeout=2s
|
||||
/radius set [find address=204.110.191.2] timeout=2s
|
||||
5
mikrotik-tool/pppoe-fix-982.rsc
Normal file
5
mikrotik-tool/pppoe-fix-982.rsc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Fix 9: Add idle timeout to PPPoE profile
|
||||
/ppp profile set [find name="982"] idle-timeout=1h
|
||||
|
||||
# Fix 10: Increase RADIUS timeout from 300ms to 2s
|
||||
/radius set [find address=204.110.191.248] timeout=2s
|
||||
2
mikrotik-tool/pppoe-fix-climax.rsc
Normal file
2
mikrotik-tool/pppoe-fix-climax.rsc
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Fix 9: Add idle timeout to PPPoE profile
|
||||
/ppp profile set [find name="pppoe"] idle-timeout=1h
|
||||
5
mikrotik-tool/pppoe-fix-core.rsc
Normal file
5
mikrotik-tool/pppoe-fix-core.rsc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Fix 9: Add idle timeout to PPPoE profile
|
||||
/ppp profile set [find name="380"] idle-timeout=1h
|
||||
|
||||
# Fix 10: Increase RADIUS timeout from 300ms to 2s
|
||||
/radius set [find address=204.110.191.248] timeout=2s
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue