npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- Enforcing identity-based network access where only authenticated and compliant devices connect to the network
- Implementing zero-trust networking at the access layer with dynamic VLAN assignment based on user role
- Quarantining non-compliant devices that fail endpoint posture checks (missing patches, disabled AV)
- Meeting compliance requirements (PCI-DSS, HIPAA, SOC 2) for network access controls
- Onboarding BYOD devices with automated provisioning and limited network access
Do not use as a standalone security solution without complementary controls, for networks with devices that do not support 802.1X supplicants, or without proper fallback mechanisms for critical infrastructure.
Prerequisites
- RADIUS server (FreeRADIUS, Microsoft NPS, or Cisco ISE) configured with user/device authentication
- Managed switches supporting 802.1X port-based authentication
- Certificate Authority for EAP-TLS certificate distribution (optional but recommended)
- PacketFence or similar NAC platform for posture assessment and remediation
- Active Directory or LDAP directory for centralized user authentication
- DHCP server integration for dynamic IP assignment per VLAN
Workflow
Step 1: Install and Configure FreeRADIUS
# Install FreeRADIUS
sudo apt install -y freeradius freeradius-utils freeradius-ldap
# Configure RADIUS clients (switches that authenticate against RADIUS)
sudo tee /etc/freeradius/3.0/clients.conf << 'EOF'
client switch-core-01 {
ipaddr = 10.10.100.1
secret = R4d1u5_S3cr3t_K3y!
shortname = core-switch
nastype = cisco
}
client switch-access-01 {
ipaddr = 10.10.100.10
secret = R4d1u5_S3cr3t_K3y!
shortname = access-switch-01
nastype = cisco
}
client switch-access-02 {
ipaddr = 10.10.100.11
secret = R4d1u5_S3cr3t_K3y!
shortname = access-switch-02
nastype = cisco
}
EOF
# Configure LDAP module for Active Directory integration
sudo tee /etc/freeradius/3.0/mods-available/ldap << 'EOF'
ldap {
server = 'ldap://dc01.corp.example.com'
identity = 'CN=radius-svc,OU=Service Accounts,DC=corp,DC=example,DC=com'
password = 'ServiceAccountPassword123!'
base_dn = 'DC=corp,DC=example,DC=com'
user {
base_dn = "${..base_dn}"
filter = "(sAMAccountName=%{%{Stripped-User-Name}:-%{User-Name}})"
}
group {
base_dn = "${..base_dn}"
filter = "(objectClass=group)"
membership_attribute = 'memberOf'
}
}
EOF
sudo ln -s /etc/freeradius/3.0/mods-available/ldap /etc/freeradius/3.0/mods-enabled/ldapStep 2: Configure VLAN Assignment Policies
# Configure authorization policies for dynamic VLAN assignment
sudo tee /etc/freeradius/3.0/policy.d/vlan-assignment << 'EOF'
# VLAN assignment based on group membership
vlan_assignment {
if (&LDAP-Group[*] == "CN=IT-Staff,OU=Groups,DC=corp,DC=example,DC=com") {
update reply {
Tunnel-Type = VLAN
Tunnel-Medium-Type = IEEE-802
Tunnel-Private-Group-ID = "10"
}
}
elsif (&LDAP-Group[*] == "CN=Developers,OU=Groups,DC=corp,DC=example,DC=com") {
update reply {
Tunnel-Type = VLAN
Tunnel-Medium-Type = IEEE-802
Tunnel-Private-Group-ID = "15"
}
}
elsif (&LDAP-Group[*] == "CN=Finance,OU=Groups,DC=corp,DC=example,DC=com") {
update reply {
Tunnel-Type = VLAN
Tunnel-Medium-Type = IEEE-802
Tunnel-Private-Group-ID = "20"
}
}
else {
# Default: Guest VLAN for unknown users
update reply {
Tunnel-Type = VLAN
Tunnel-Medium-Type = IEEE-802
Tunnel-Private-Group-ID = "40"
}
}
}
EOF
# Add vlan_assignment to the authorize section
# Edit /etc/freeradius/3.0/sites-enabled/default
# In the authorize section, add: vlan_assignment
# Configure EAP for 802.1X authentication
sudo tee /etc/freeradius/3.0/mods-available/eap << 'EAPEOF'
eap {
default_eap_type = peap
timer_expire = 60
max_sessions = 4096
tls-config tls-common {
private_key_file = /etc/freeradius/3.0/certs/server.key
certificate_file = /etc/freeradius/3.0/certs/server.pem
ca_file = /etc/freeradius/3.0/certs/ca.pem
dh_file = /etc/freeradius/3.0/certs/dh
cipher_list = "HIGH:!aNULL:!MD5"
tls_min_version = "1.2"
}
peap {
tls = tls-common
default_eap_type = mschapv2
virtual_server = inner-tunnel
}
tls {
tls = tls-common
}
}
EAPEOF
# Start FreeRADIUS in debug mode for testing
sudo freeradius -X
# Test authentication
radtest testuser TestPassword123 localhost 0 testing123Step 3: Configure 802.1X on Cisco Switches
! Enable AAA on the switch
enable
configure terminal
aaa new-model
aaa authentication dot1x default group radius
aaa authorization network default group radius
aaa accounting dot1x default start-stop group radius
! Configure RADIUS server
radius server FREERADIUS
address ipv4 10.10.100.200 auth-port 1812 acct-port 1813
key R4d1u5_S3cr3t_K3y!
exit
! Enable 802.1X globally
dot1x system-auth-control
! Configure access ports for 802.1X
interface range GigabitEthernet1/0/1-24
switchport mode access
switchport access vlan 999
authentication port-control auto
authentication order dot1x mab
authentication priority dot1x mab
dot1x pae authenticator
dot1x timeout tx-period 10
mab
authentication event fail action authorize vlan 999
authentication event no-response action authorize vlan 40
authentication host-mode multi-auth
spanning-tree portfast
exit
! Configure MAB (MAC Authentication Bypass) for devices without 802.1X
! Devices like printers, IP phones that cannot run a supplicant
interface range GigabitEthernet1/0/25-36
switchport mode access
switchport access vlan 999
authentication port-control auto
authentication order mab
mab
authentication event fail action authorize vlan 999
authentication host-mode single-host
spanning-tree portfast
exit
! Configure guest VLAN for unauthenticated devices
interface range GigabitEthernet1/0/1-24
authentication event no-response action authorize vlan 40
authentication event fail action authorize vlan 999
exit
! Configure critical VLAN for RADIUS server unavailability
interface range GigabitEthernet1/0/1-36
authentication event server dead action authorize vlan 10
authentication event server alive action reinitialize
exitStep 4: Deploy PacketFence NAC for Posture Assessment
# Install PacketFence
curl -fsSL https://inverse.ca/downloads/GPG_PUBLIC_KEY | sudo gpg --dearmor -o /etc/apt/keyrings/inverse.gpg
echo "deb [signed-by=/etc/apt/keyrings/inverse.gpg] https://inverse.ca/downloads/PacketFence/debian bookworm bookworm" | \
sudo tee /etc/apt/sources.list.d/packetfence.list
sudo apt update && sudo apt install -y packetfence
# Run the PacketFence configurator
sudo /usr/local/pf/bin/pfcmd configreload
# Access web admin: https://<packetfence-ip>:1443
# Configure PacketFence connection profiles
# Admin UI: Configuration > Policies and Access Control > Connection Profiles
# Create compliance check (Windows Update status)
# Admin UI: Configuration > Compliance > Scan Engines
# Add: Windows Update compliance check
# Remediation VLAN: 999 (quarantine)
# Configure RADIUS integration
# PacketFence acts as a RADIUS proxy, receiving requests from switches
# and enforcing posture-based VLAN assignment
# Edit /usr/local/pf/conf/switches.conf
sudo tee -a /usr/local/pf/conf/switches.conf << 'EOF'
[10.10.100.10]
description=Access Switch 01
type=Cisco::Catalyst_2960
mode=production
radiusSecret=R4d1u5_S3cr3t_K3y!
SNMPVersion=2c
SNMPCommunityRead=public
SNMPCommunityWrite=private
VlanMap=Y
registrationVlan=40
isolationVlan=999
normalVlan=10
EOFStep 5: Configure Supplicant on Endpoints
# Windows Group Policy for 802.1X configuration
# Computer Configuration > Policies > Windows Settings > Security Settings
# > System Services > Wired AutoConfig: Automatic
# > Network Policies:
# Authentication method: Microsoft: Protected EAP (PEAP)
# Inner method: EAP-MSCHAPv2
# Trusted Root CA: Corporate CA
# Linux 802.1X configuration with wpa_supplicant
sudo tee /etc/wpa_supplicant/wpa_supplicant-wired.conf << 'EOF'
ctrl_interface=/var/run/wpa_supplicant
ap_scan=0
network={
key_mgmt=IEEE8021X
eap=PEAP
identity="testuser@corp.example.com"
password="UserPassword123"
ca_cert="/etc/ssl/certs/corporate-ca.pem"
phase2="auth=MSCHAPV2"
}
EOF
# Start wpa_supplicant for wired 802.1X
sudo wpa_supplicant -i eth0 -D wired -c /etc/wpa_supplicant/wpa_supplicant-wired.conf -B
# Verify authentication status
wpa_cli -i eth0 status
# macOS: System Preferences > Network > Ethernet > 802.1X
# Configure with PEAP and corporate credentialsStep 6: Test and Validate NAC Deployment
# Test 1: Authenticated device gets correct VLAN
# Connect a corporate laptop with 802.1X configured
# Verify VLAN assignment on the switch:
# show authentication sessions interface Gi1/0/1
# Expected:
# Session ID: 0A0A0A01000000010001
# Status: Authorized
# Domain: DATA
# Oper host mode: multi-auth
# Oper control dir: both
# Authorized By: Authentication Server
# Vlan Policy: 10
# Test 2: Unauthenticated device goes to guest VLAN
# Connect a device without 802.1X supplicant
# show authentication sessions interface Gi1/0/2
# Expected: Vlan Policy: 40 (Guest)
# Test 3: Failed authentication goes to quarantine
# Attempt authentication with wrong credentials
# Expected: Vlan Policy: 999 (Quarantine)
# Test 4: RADIUS server failure - critical VLAN
# Stop FreeRADIUS temporarily
# Connect a new device
# Expected: Vlan Policy: 10 (Critical/failover)
# Test 5: MAC Authentication Bypass
# Connect a printer (no supplicant)
# MAB should authenticate based on MAC address in RADIUS
# show authentication sessions interface Gi1/0/25
# Generate authentication report
# show authentication sessions | include Auth
# show dot1x all summaryKey Concepts
| Term | Definition |
|---|---|
| 802.1X | IEEE standard for port-based network access control that authenticates devices before granting network access via EAP and RADIUS |
| RADIUS | Remote Authentication Dial-In User Service protocol used by network devices to authenticate users and receive authorization attributes (VLAN, ACL) |
| MAB (MAC Authentication Bypass) | Fallback authentication method that uses a device's MAC address as credentials for devices that cannot run an 802.1X supplicant |
| EAP-PEAP | Protected Extensible Authentication Protocol that wraps EAP in a TLS tunnel, commonly used with MSCHAPv2 for username/password authentication |
| Posture Assessment | Evaluation of endpoint compliance status (OS patches, antivirus, encryption) before granting full network access |
| Dynamic VLAN Assignment | RADIUS-driven automatic VLAN placement based on user identity, group membership, or device type, eliminating static port-based VLAN configuration |
Tools & Systems
- FreeRADIUS: Open-source RADIUS server supporting EAP-TLS, PEAP, LDAP integration, and dynamic VLAN assignment
- PacketFence: Open-source NAC solution providing 802.1X integration, posture assessment, captive portal, and device registration
- Cisco ISE: Enterprise NAC platform with profiling, posture, guest management, and TrustSec integration
- wpa_supplicant: Open-source 802.1X supplicant for Linux and embedded systems supporting EAP-TLS, PEAP, and TTLS
- Microsoft NPS: Windows Server RADIUS implementation integrating natively with Active Directory for 802.1X authentication
Common Scenarios
Scenario: Deploying 802.1X NAC in a Hospital Network
Context: A hospital needs to enforce network access control to meet HIPAA requirements. The network includes clinical workstations (domain-joined), medical devices (no 802.1X support), physician BYOD devices, and guest WiFi. The deployment must not disrupt patient care if the RADIUS server becomes unavailable.
Approach:
- Deploy FreeRADIUS integrated with Active Directory for user authentication and group-based VLAN assignment
- Configure domain-joined workstations for EAP-PEAP via Group Policy with auto-enrollment
- Register medical devices (infusion pumps, monitors) for MAB authentication using their MAC addresses in the RADIUS database
- Configure switches with authentication order dot1x then mab, with critical VLAN fallback to the clinical VLAN if RADIUS is unreachable
- Deploy PacketFence captive portal for physician BYOD onboarding with limited-access VLAN
- Configure posture checks requiring Windows Update compliance and BitLocker encryption for full access
- Test failover scenarios by stopping RADIUS and verifying devices remain on critical VLAN without disruption
Pitfalls:
- Not configuring critical VLAN fallback, causing devices to lose network access when RADIUS is unavailable
- MAB MAC address databases becoming stale as medical devices are replaced or moved
- 802.1X timeouts causing delays at workstation login, especially with slow RADIUS responses
- Not testing multi-host mode on ports with IP phones and workstations daisy-chained
Output Format
## NAC Deployment Report
**RADIUS Server**: freeradius-01 (10.10.100.200)
**NAC Platform**: PacketFence 13.1
**Switches Configured**: 12 access switches
**Total Ports**: 576 access ports
### Authentication Summary (24-hour)
| Auth Type | Success | Failure | Total |
|-----------|---------|---------|-------|
| 802.1X (PEAP) | 342 | 12 | 354 |
| MAB | 87 | 3 | 90 |
| Guest Portal | 23 | 5 | 28 |
### VLAN Assignment Distribution
| VLAN | Name | Assigned Devices |
|------|------|------------------|
| 10 | Corporate | 245 |
| 15 | Development | 67 |
| 20 | Finance | 30 |
| 40 | Guest | 23 |
| 50 | Medical Devices | 87 |
| 999 | Quarantine | 15 (posture fail) |
### Compliance Status
- 802.1X coverage: 100% of access ports
- Posture pass rate: 95.8% (15 devices quarantined for missing patches)
- RADIUS failover tested: Successful (critical VLAN activated in 3 seconds)References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.0 KB
API Reference: Implementing Network Access Control
Libraries
pyrad (RADIUS Client)
- Install:
pip install pyrad - Docs: https://pypi.org/project/pyrad/
Client(server, secret, dict)-- Create RADIUS clientCreateAuthPacket()-- Build Access-RequestSendPacket(req)-- Send and receive RADIUS reply- Response codes:
AccessAccept,AccessReject,AccessChallenge
pysnmp (SNMP for Switch Queries)
- Install:
pip install pysnmp - Docs: https://pysnmp.readthedocs.io/
getCmd()-- SNMP GET requestnextCmd()-- SNMP GETNEXT/walkCommunityData()-- SNMPv2c community stringUsmUserData()-- SNMPv3 authentication
802.1X SNMP OIDs
| OID | Description |
|---|---|
1.3.6.1.2.1.8802.1.1.1.1.2.1.1.1 |
dot1xAuthAuthControlledPortStatus |
1.3.6.1.2.1.8802.1.1.1.1.2.1.1.2 |
dot1xAuthAuthControlledPortControl |
1.3.6.1.2.1.8802.1.1.1.1.2.4.1.1 |
dot1xAuthSessionAuthenticMethod |
RADIUS Attributes
| Attribute | Use |
|---|---|
User-Name |
Client identity |
User-Password |
PAP password |
NAS-IP-Address |
Switch/AP IP |
NAS-Port-Type |
Port type (Ethernet, Wireless) |
Tunnel-Type |
VLAN assignment (13 = VLAN) |
Tunnel-Medium-Type |
Medium (6 = 802) |
Tunnel-Private-Group-Id |
VLAN ID for dynamic assignment |
Filter-Id |
ACL name to apply |
EAP Methods
- EAP-TLS: Certificate-based (strongest, requires PKI)
- PEAP: Password with TLS tunnel
- EAP-TTLS: Tunneled TLS (flexible inner auth)
- MAB: MAC Authentication Bypass (fallback, no supplicant)
PacketFence NAC API
- REST API at
https://packetfence:9999/api/v1/ GET /nodes-- List known devicesPOST /nodes/{mac}/register-- Register deviceGET /violations-- Active violations
External References
- FreeRADIUS: https://freeradius.org/documentation/
- PacketFence NAC: https://www.packetfence.org/doc/
- Cisco ISE: https://developer.cisco.com/docs/identity-services-engine/
- 802.1X RFC 3748: https://datatracker.ietf.org/doc/html/rfc3748
Scripts 1
agent.py8.6 KB
#!/usr/bin/env python3
"""Network Access Control (802.1X/NAC) monitoring agent using RADIUS and SNMP."""
import json
import sys
import argparse
from datetime import datetime
from collections import Counter
try:
from pyrad.client import Client
from pyrad.dictionary import Dictionary
from pyrad import packet
except ImportError:
print("Install pyrad: pip install pyrad")
sys.exit(1)
try:
from pysnmp.hlapi import nextCmd, SnmpEngine, CommunityData, UdpTransportTarget, ContextData, ObjectType, ObjectIdentity
HAS_SNMP = True
except ImportError:
HAS_SNMP = False
def test_radius_auth(server, secret, username, password, port=1812):
"""Test RADIUS authentication for a user credential pair."""
srv = Client(server=server, secret=secret.encode(),
dict=Dictionary(dict_file=None))
srv.AuthPort = port
req = srv.CreateAuthPacket(code=packet.AccessRequest, User_Name=username)
req["User-Password"] = req.PwCrypt(password)
req["NAS-IP-Address"] = "192.168.1.1"
req["NAS-Port-Type"] = "Ethernet"
req["NAS-Port"] = 1
try:
reply = srv.SendPacket(req)
if reply.code == packet.AccessAccept:
attrs = {}
for key in reply.keys():
attrs[key] = reply[key]
return {"status": "ACCEPT", "user": username, "attributes": str(attrs)}
elif reply.code == packet.AccessReject:
return {"status": "REJECT", "user": username, "reason": "Invalid credentials"}
elif reply.code == packet.AccessChallenge:
return {"status": "CHALLENGE", "user": username, "reason": "Additional auth required"}
except Exception as e:
return {"status": "ERROR", "user": username, "error": str(e)}
def parse_radius_log(log_file, max_lines=1000):
"""Parse FreeRADIUS log file for authentication events."""
events = []
try:
with open(log_file, "r") as f:
for i, line in enumerate(f):
if i >= max_lines:
break
if "Auth:" in line or "Login" in line:
parts = line.strip().split()
event = {"raw": line.strip(), "timestamp": " ".join(parts[:3]) if len(parts) > 3 else ""}
if "Login OK" in line:
event["result"] = "SUCCESS"
elif "Login incorrect" in line:
event["result"] = "FAILURE"
elif "Invalid user" in line:
event["result"] = "INVALID_USER"
else:
event["result"] = "OTHER"
events.append(event)
except FileNotFoundError:
events.append({"error": f"Log file not found: {log_file}"})
return events
def check_switch_port_status(switch_ip, community="public"):
"""Query switch via SNMP for 802.1X port authentication status."""
if not HAS_SNMP:
return [{"error": "pysnmp not installed. Run: pip install pysnmp"}]
dot1x_auth_oid = "1.3.6.1.2.1.8802.1.1.1.1.2.1.1.1"
results = []
iterator = nextCmd(
SnmpEngine(), CommunityData(community),
UdpTransportTarget((switch_ip, 161)),
ContextData(),
ObjectType(ObjectIdentity(dot1x_auth_oid)),
maxRows=100)
for errorIndication, errorStatus, errorIndex, varBinds in iterator:
if errorIndication or errorStatus:
results.append({"error": str(errorIndication or errorStatus)})
break
for varBind in varBinds:
oid, value = varBind
port_index = str(oid).split(".")[-1]
auth_states = {1: "initialize", 2: "disconnected", 3: "connecting",
4: "authenticating", 5: "authenticated",
6: "aborting", 7: "held", 8: "forceAuth", 9: "forceUnauth"}
results.append({
"port": port_index,
"state": auth_states.get(int(value), f"unknown({value})"),
"state_code": int(value)
})
return results
def analyze_auth_events(events):
"""Analyze authentication events for security issues."""
result_counts = Counter(e.get("result", "UNKNOWN") for e in events)
total = len(events)
failures = result_counts.get("FAILURE", 0) + result_counts.get("INVALID_USER", 0)
success_rate = round((result_counts.get("SUCCESS", 0) / max(total, 1)) * 100, 1)
analysis = {
"total_events": total,
"successes": result_counts.get("SUCCESS", 0),
"failures": failures,
"invalid_users": result_counts.get("INVALID_USER", 0),
"success_rate": success_rate,
"risk_level": "HIGH" if failures > total * 0.3 else "MEDIUM" if failures > total * 0.1 else "LOW",
}
if failures > 20:
analysis["alert"] = "High number of authentication failures - possible brute force attack"
return analysis
def generate_nac_policy_check():
"""Generate a NAC compliance policy checklist."""
policies = [
{"check": "802.1X enforcement", "requirement": "All access ports configured for dot1x",
"standard": "PCI-DSS 1.2"},
{"check": "Guest VLAN isolation", "requirement": "Unauthenticated devices on restricted VLAN",
"standard": "NIST 800-53 AC-4"},
{"check": "MAB fallback", "requirement": "MAC Authentication Bypass for non-supplicant devices",
"standard": "Best Practice"},
{"check": "EAP-TLS certificates", "requirement": "Certificate-based auth for managed devices",
"standard": "NIST 800-53 IA-5"},
{"check": "Posture assessment", "requirement": "Endpoint compliance check before full access",
"standard": "PCI-DSS 5.3"},
{"check": "Dynamic VLAN assignment", "requirement": "Role-based VLAN via RADIUS attributes",
"standard": "NIST 800-53 AC-6"},
{"check": "Re-authentication timer", "requirement": "Periodic re-auth every 3600 seconds",
"standard": "Best Practice"},
{"check": "RADIUS accounting", "requirement": "Accounting enabled for audit trail",
"standard": "SOC 2 CC6.1"},
]
return policies
def run_nac_audit(radius_log=None, switch_ip=None, community="public"):
"""Run NAC security audit."""
print(f"\n{'='*60}")
print(f" NETWORK ACCESS CONTROL AUDIT")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
policies = generate_nac_policy_check()
print(f"--- NAC POLICY CHECKLIST ---")
for p in policies:
print(f" [ ] {p['check']}: {p['requirement']} ({p['standard']})")
if radius_log:
events = parse_radius_log(radius_log)
analysis = analyze_auth_events(events)
print(f"\n--- RADIUS AUTH ANALYSIS ---")
print(f" Total Events: {analysis['total_events']}")
print(f" Successes: {analysis['successes']}")
print(f" Failures: {analysis['failures']}")
print(f" Success Rate: {analysis['success_rate']}%")
print(f" Risk Level: {analysis['risk_level']}")
if analysis.get("alert"):
print(f" ALERT: {analysis['alert']}")
if switch_ip:
ports = check_switch_port_status(switch_ip, community)
print(f"\n--- SWITCH PORT STATUS ({switch_ip}) ---")
for p in ports[:20]:
if "error" in p:
print(f" Error: {p['error']}")
else:
icon = "[OK]" if p["state"] == "authenticated" else "[!!]"
print(f" {icon} Port {p['port']}: {p['state']}")
print(f"\n{'='*60}\n")
return {"policies": policies}
def main():
parser = argparse.ArgumentParser(description="Network Access Control Agent")
parser.add_argument("--audit", action="store_true", help="Run NAC audit")
parser.add_argument("--radius-log", help="Path to FreeRADIUS log file")
parser.add_argument("--switch", help="Switch IP for SNMP 802.1X status check")
parser.add_argument("--community", default="public", help="SNMP community string")
parser.add_argument("--test-auth", nargs=4, metavar=("SERVER", "SECRET", "USER", "PASS"),
help="Test RADIUS authentication")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
if args.test_auth:
result = test_radius_auth(*args.test_auth)
print(json.dumps(result, indent=2))
elif args.audit:
report = run_nac_audit(args.radius_log, args.switch, args.community)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
else:
parser.print_help()
if __name__ == "__main__":
main()