mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-30 18:27:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2816 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2816 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| // Created by stephane bourque on 2021-09-14.
 | |
| //
 | |
| 
 | |
| #include <iostream>
 | |
| #include <fstream>
 | |
| #include <regex>
 | |
| 
 | |
| #include "framework/MicroService.h"
 | |
| #include "ConfigurationValidator.h"
 | |
| #include "framework/CountryCodes.h"
 | |
| #include "Poco/StringTokenizer.h"
 | |
| 
 | |
| namespace OpenWifi {
 | |
| 
 | |
| static const std::string GitUCentralJSONSchemaFile{
 | |
| 	"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"};
 | |
| 
 | |
| static json DefaultUCentralSchema = R"(
 | |
| 
 | |
| {
 | |
| 	"$id": "https://openwrt.org/ucentral.schema.json",
 | |
| 	"$schema": "http://json-schema.org/draft-07/schema#",
 | |
| 	"type": "object",
 | |
| 	"properties": {
 | |
| 		"uuid": {
 | |
| 			"type": "integer"
 | |
| 		},
 | |
| 		"unit": {
 | |
| 			"$ref": "#/$defs/unit"
 | |
| 		},
 | |
| 		"globals": {
 | |
| 			"$ref": "#/$defs/globals"
 | |
| 		},
 | |
| 		"definitions": {
 | |
| 			"$ref": "#/$defs/definitions"
 | |
| 		},
 | |
| 		"ethernet": {
 | |
| 			"type": "array",
 | |
| 			"items": {
 | |
| 				"$ref": "#/$defs/ethernet"
 | |
| 			}
 | |
| 		},
 | |
| 		"switch": {
 | |
| 			"$ref": "#/$defs/switch"
 | |
| 		},
 | |
| 		"radios": {
 | |
| 			"type": "array",
 | |
| 			"items": {
 | |
| 				"$ref": "#/$defs/radio"
 | |
| 			}
 | |
| 		},
 | |
| 		"interfaces": {
 | |
| 			"type": "array",
 | |
| 			"items": {
 | |
| 				"$ref": "#/$defs/interface"
 | |
| 			}
 | |
| 		},
 | |
| 		"services": {
 | |
| 			"$ref": "#/$defs/service"
 | |
| 		},
 | |
| 		"metrics": {
 | |
| 			"$ref": "#/$defs/metrics"
 | |
| 		},
 | |
| 		"config-raw": {
 | |
| 			"$ref": "#/$defs/config-raw"
 | |
| 		},
 | |
| 		"third-party": {
 | |
| 			"type": "object",
 | |
| 			"additionalProperties": true
 | |
| 		}
 | |
| 	},
 | |
| 	"$defs": {
 | |
| 		"unit": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"name": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"hostname": {
 | |
| 					"type": "string",
 | |
| 					"format": "hostname"
 | |
| 				},
 | |
| 				"location": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"timezone": {
 | |
| 					"type": "string",
 | |
| 					"examples": [
 | |
| 						"UTC",
 | |
| 						"EST5",
 | |
| 						"CET-1CEST,M3.5.0,M10.5.0/3"
 | |
| 					]
 | |
| 				},
 | |
| 				"leds-active": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				},
 | |
| 				"random-password": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"globals.wireless-multimedia.class-selector": {
 | |
| 			"type": "array",
 | |
| 			"items": {
 | |
| 				"type": "string",
 | |
| 				"enum": [
 | |
| 					"CS0",
 | |
| 					"CS1",
 | |
| 					"CS2",
 | |
| 					"CS3",
 | |
| 					"CS4",
 | |
| 					"CS5",
 | |
| 					"CS6",
 | |
| 					"CS7",
 | |
| 					"AF11",
 | |
| 					"AF12",
 | |
| 					"AF13",
 | |
| 					"AF21",
 | |
| 					"AF22",
 | |
| 					"AF23",
 | |
| 					"AF31",
 | |
| 					"AF32",
 | |
| 					"AF33",
 | |
| 					"AF41",
 | |
| 					"AF42",
 | |
| 					"AF43",
 | |
| 					"DF",
 | |
| 					"EF",
 | |
| 					"VA",
 | |
| 					"LE"
 | |
| 				]
 | |
| 			}
 | |
| 		},
 | |
| 		"globals.wireless-multimedia.table": {
 | |
| 			"type": "object",
 | |
| 			"additionalProperties": false,
 | |
| 			"properties": {
 | |
| 				"UP0": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP1": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP2": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP3": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP4": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP5": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP6": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				},
 | |
| 				"UP7": {
 | |
| 					"$ref": "#/$defs/globals.wireless-multimedia.class-selector"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"globals.wireless-multimedia.profile": {
 | |
| 			"type": "object",
 | |
| 			"additionalProperties": false,
 | |
| 			"properties": {
 | |
| 				"profile": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"enterprise",
 | |
| 						"rfc8325",
 | |
| 						"3gpp"
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"globals": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"ipv4-network": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-cidr4",
 | |
| 					"examples": [
 | |
| 						"192.168.0.0/16"
 | |
| 					]
 | |
| 				},
 | |
| 				"ipv6-network": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-cidr6",
 | |
| 					"examples": [
 | |
| 						"fdca:1234:4567::/48"
 | |
| 					]
 | |
| 				},
 | |
| 				"wireless-multimedia": {
 | |
| 					"anyOf": [{
 | |
| 							"$ref": "#/$defs/globals.wireless-multimedia.table"
 | |
| 						},
 | |
| 						{
 | |
| 							"$ref": "#/$defs/globals.wireless-multimedia.profile"
 | |
| 						}
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"definitions": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"wireless-encryption": {
 | |
| 					"type": "object",
 | |
| 					"patternProperties": {
 | |
| 						".+": {
 | |
| 							"$ref": "#/$defs/interface.ssid.encryption",
 | |
| 							"additionalProperties": false
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"ethernet": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"select-ports": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"LAN1",
 | |
| 							"LAN2",
 | |
| 							"LAN3",
 | |
| 							"LAN4",
 | |
| 							"LAN*",
 | |
| 							"WAN*",
 | |
| 							"*"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"speed": {
 | |
| 					"type": "integer",
 | |
| 					"enum": [
 | |
| 						10,
 | |
| 						100,
 | |
| 						1000,
 | |
| 						2500,
 | |
| 						5000,
 | |
| 						10000
 | |
| 					]
 | |
| 				},
 | |
| 				"duplex": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"half",
 | |
| 						"full"
 | |
| 					]
 | |
| 				},
 | |
| 				"services": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"quality-of-service"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"switch": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"port-mirror": {
 | |
| 					"type": "object",
 | |
| 					"properties": {
 | |
| 						"monitor-ports": {
 | |
| 							"type": "array",
 | |
| 							"items": {
 | |
| 								"type": "string"
 | |
| 							}
 | |
| 						},
 | |
| 						"analysis-port": {
 | |
| 							"type": "string"
 | |
| 						}
 | |
| 					}
 | |
| 				},
 | |
| 				"loop-detection": {
 | |
| 					"type": "object",
 | |
| 					"properties": {
 | |
| 						"protocol": {
 | |
| 							"type": "string",
 | |
| 							"enum": [
 | |
| 								"rstp"
 | |
| 							],
 | |
| 							"default": "rstp"
 | |
| 						},
 | |
| 						"roles": {
 | |
| 							"type": "array",
 | |
| 							"items": {
 | |
| 								"type": "string",
 | |
| 								"enum": [
 | |
| 									"upstream",
 | |
| 									"downstream"
 | |
| 								]
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"radio.rates": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"beacon": {
 | |
| 					"type": "integer",
 | |
| 					"default": 6000,
 | |
| 					"enum": [
 | |
| 						0,
 | |
| 						1000,
 | |
| 						2000,
 | |
| 						5500,
 | |
| 						6000,
 | |
| 						9000,
 | |
| 						11000,
 | |
| 						12000,
 | |
| 						18000,
 | |
| 						24000,
 | |
| 						36000,
 | |
| 						48000,
 | |
| 						54000
 | |
| 					]
 | |
| 				},
 | |
| 				"multicast": {
 | |
| 					"type": "integer",
 | |
| 					"default": 24000,
 | |
| 					"enum": [
 | |
| 						0,
 | |
| 						1000,
 | |
| 						2000,
 | |
| 						5500,
 | |
| 						6000,
 | |
| 						9000,
 | |
| 						11000,
 | |
| 						12000,
 | |
| 						18000,
 | |
| 						24000,
 | |
| 						36000,
 | |
| 						48000,
 | |
| 						54000
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"radio.he": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"multiple-bssid": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"ema": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"bss-color": {
 | |
| 					"type": "integer",
 | |
| 					"default": 64
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"radio": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"band": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"2G",
 | |
| 						"5G",
 | |
| 						"5G-lower",
 | |
| 						"5G-upper",
 | |
| 						"6G"
 | |
| 					]
 | |
| 				},
 | |
| 				"bandwidth": {
 | |
| 					"type": "integer",
 | |
| 					"enum": [
 | |
| 						5,
 | |
| 						10,
 | |
| 						20
 | |
| 					]
 | |
| 				},
 | |
| 				"channel": {
 | |
| 					"oneOf": [{
 | |
| 							"type": "integer",
 | |
| 							"maximum": 196,
 | |
| 							"minimum": 1
 | |
| 						},
 | |
| 						{
 | |
| 							"type": "string",
 | |
| 							"const": "auto"
 | |
| 						}
 | |
| 					]
 | |
| 				},
 | |
| 				"valid-channels": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "integer",
 | |
| 						"maximum": 196,
 | |
| 						"minimum": 1
 | |
| 					}
 | |
| 				},
 | |
| 				"country": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 2,
 | |
| 					"minLength": 2,
 | |
| 					"examples": [
 | |
| 						"US"
 | |
| 					]
 | |
| 				},
 | |
| 				"allow-dfs": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				},
 | |
| 				"channel-mode": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"HT",
 | |
| 						"VHT",
 | |
| 						"HE"
 | |
| 					],
 | |
| 					"default": "HE"
 | |
| 				},
 | |
| 				"channel-width": {
 | |
| 					"type": "integer",
 | |
| 					"enum": [
 | |
| 						20,
 | |
| 						40,
 | |
| 						80,
 | |
| 						160,
 | |
| 						8080
 | |
| 					],
 | |
| 					"default": 80
 | |
| 				},
 | |
| 				"require-mode": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"HT",
 | |
| 						"VHT",
 | |
| 						"HE"
 | |
| 					]
 | |
| 				},
 | |
| 				"mimo": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"1x1",
 | |
| 						"2x2",
 | |
| 						"3x3",
 | |
| 						"4x4",
 | |
| 						"5x5",
 | |
| 						"6x6",
 | |
| 						"7x7",
 | |
| 						"8x8"
 | |
| 					]
 | |
| 				},
 | |
| 				"tx-power": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 30,
 | |
| 					"minimum": 0
 | |
| 				},
 | |
| 				"legacy-rates": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"beacon-interval": {
 | |
| 					"type": "integer",
 | |
| 					"default": 100,
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 15
 | |
| 				},
 | |
| 				"dtim-period": {
 | |
| 					"type": "integer",
 | |
| 					"default": 2,
 | |
| 					"maximum": 255,
 | |
| 					"minimum": 1
 | |
| 				},
 | |
| 				"maximum-clients": {
 | |
| 					"type": "integer",
 | |
| 					"example": 64
 | |
| 				},
 | |
| 				"rates": {
 | |
| 					"$ref": "#/$defs/radio.rates"
 | |
| 				},
 | |
| 				"he-settings": {
 | |
| 					"$ref": "#/$defs/radio.he"
 | |
| 				},
 | |
| 				"hostapd-iface-raw": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"ap_table_expiration_time=3600",
 | |
| 							"device_type=6-0050F204-1",
 | |
| 							"ieee80211h=1",
 | |
| 							"rssi_ignore_probe_request=-75",
 | |
| 							"time_zone=EST5",
 | |
| 							"uuid=12345678-9abc-def0-1234-56789abcdef0",
 | |
| 							"venue_url=1:http://www.example.com/info-eng",
 | |
| 							"wpa_deny_ptk0_rekey=0"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.vlan": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"id": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 4050
 | |
| 				},
 | |
| 				"proto": {
 | |
| 					"decription": "The L2 vlan tag that shall be added (1q,1ad ) ",
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"802.1ad",
 | |
| 						"802.1q"
 | |
| 					],
 | |
| 					"default": "802.1q"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.bridge": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"mtu": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 256,
 | |
| 					"examples": [
 | |
| 						1500
 | |
| 					]
 | |
| 				},
 | |
| 				"tx-queue-len": {
 | |
| 					"type": "integer",
 | |
| 					"examples": [
 | |
| 						5000
 | |
| 					]
 | |
| 				},
 | |
| 				"isolate-ports": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ethernet": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"select-ports": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"LAN1",
 | |
| 							"LAN2",
 | |
| 							"LAN3",
 | |
| 							"LAN4",
 | |
| 							"LAN*",
 | |
| 							"WAN*",
 | |
| 							"*"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"multicast": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				},
 | |
| 				"learning": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				},
 | |
| 				"isolate": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"macaddr": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-mac"
 | |
| 				},
 | |
| 				"reverse-path-filter": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"vlan-tag": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"tagged",
 | |
| 						"un-tagged",
 | |
| 						"auto"
 | |
| 					],
 | |
| 					"default": "auto"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ipv4.dhcp": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"lease-first": {
 | |
| 					"type": "integer",
 | |
| 					"examples": [
 | |
| 						10
 | |
| 					]
 | |
| 				},
 | |
| 				"lease-count": {
 | |
| 					"type": "integer",
 | |
| 					"examples": [
 | |
| 						100
 | |
| 					]
 | |
| 				},
 | |
| 				"lease-time": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-timeout",
 | |
| 					"default": "6h"
 | |
| 				},
 | |
| 				"relay-server": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv4",
 | |
| 					"example": "192.168.2.1"
 | |
| 				},
 | |
| 				"circuit-id-format": {
 | |
| 					"type": "string",
 | |
| 					"example": [
 | |
| 						"\\{Interface\\}:\\{VLAN-Id\\}:\\{SSID\\}:\\{Model\\}:\\{Name\\}:\\{AP-MAC\\}:\\{Location\\}",
 | |
| 						"\\{AP-MAC\\};\\{SSID\\};\\{Crypto\\}",
 | |
| 						"\\{Name\\} \\{ESSID\\}"
 | |
| 					]
 | |
| 				},
 | |
| 				"remote-id-format": {
 | |
| 					"type": "string",
 | |
| 					"example": [
 | |
| 						"\\{Client-MAC-hex\\} \\{SSID\\}",
 | |
| 						"\\{AP-MAC-hex\\} \\{SSID\\}"
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ipv4.dhcp-lease": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"macaddr": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-mac",
 | |
| 					"examples": [
 | |
| 						"00:11:22:33:44:55"
 | |
| 					]
 | |
| 				},
 | |
| 				"static-lease-offset": {
 | |
| 					"type": "integer",
 | |
| 					"examples": [
 | |
| 						10
 | |
| 					]
 | |
| 				},
 | |
| 				"lease-time": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-timeout",
 | |
| 					"default": "6h"
 | |
| 				},
 | |
| 				"publish-hostname": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ipv4.port-forward": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"protocol": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"tcp",
 | |
| 						"udp",
 | |
| 						"any"
 | |
| 					],
 | |
| 					"default": "any"
 | |
| 				},
 | |
| 				"external-port": {
 | |
| 					"type": [
 | |
| 						"integer",
 | |
| 						"string"
 | |
| 					],
 | |
| 					"minimum": 0,
 | |
| 					"maximum": 65535,
 | |
| 					"format": "uc-portrange"
 | |
| 				},
 | |
| 				"internal-address": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv4",
 | |
| 					"example": "0.0.0.120"
 | |
| 				},
 | |
| 				"internal-port": {
 | |
| 					"type": [
 | |
| 						"integer",
 | |
| 						"string"
 | |
| 					],
 | |
| 					"minimum": 0,
 | |
| 					"maximum": 65535,
 | |
| 					"format": "uc-portrange"
 | |
| 				}
 | |
| 			},
 | |
| 			"required": [
 | |
| 				"external-port",
 | |
| 				"internal-address"
 | |
| 			]
 | |
| 		},
 | |
| 		"interface.ipv4": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"addressing": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"dynamic",
 | |
| 						"static"
 | |
| 					],
 | |
| 					"examples": [
 | |
| 						"static"
 | |
| 					]
 | |
| 				},
 | |
| 				"subnet": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-cidr4",
 | |
| 					"examples": [
 | |
| 						"auto/24"
 | |
| 					]
 | |
| 				},
 | |
| 				"gateway": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv4",
 | |
| 					"examples": [
 | |
| 						"192.168.1.1"
 | |
| 					]
 | |
| 				},
 | |
| 				"send-hostname": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true,
 | |
| 					"examples": [
 | |
| 						true
 | |
| 					]
 | |
| 				},
 | |
| 				"use-dns": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"format": "ipv4",
 | |
| 						"examples": [
 | |
| 							"8.8.8.8",
 | |
| 							"4.4.4.4"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"dhcp": {
 | |
| 					"$ref": "#/$defs/interface.ipv4.dhcp"
 | |
| 				},
 | |
| 				"dhcp-leases": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ipv4.dhcp-lease"
 | |
| 					}
 | |
| 				},
 | |
| 				"port-forward": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ipv4.port-forward"
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ipv6.dhcpv6": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"mode": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"hybrid",
 | |
| 						"stateless",
 | |
| 						"stateful",
 | |
| 						"relay"
 | |
| 					]
 | |
| 				},
 | |
| 				"announce-dns": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"format": "ipv6"
 | |
| 					}
 | |
| 				},
 | |
| 				"filter-prefix": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-cidr6",
 | |
| 					"default": "::/0"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ipv6.port-forward": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"protocol": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"tcp",
 | |
| 						"udp",
 | |
| 						"any"
 | |
| 					],
 | |
| 					"default": "any"
 | |
| 				},
 | |
| 				"external-port": {
 | |
| 					"type": [
 | |
| 						"integer",
 | |
| 						"string"
 | |
| 					],
 | |
| 					"minimum": 0,
 | |
| 					"maximum": 65535,
 | |
| 					"format": "uc-portrange"
 | |
| 				},
 | |
| 				"internal-address": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv6",
 | |
| 					"example": "::1234:abcd"
 | |
| 				},
 | |
| 				"internal-port": {
 | |
| 					"type": [
 | |
| 						"integer",
 | |
| 						"string"
 | |
| 					],
 | |
| 					"minimum": 0,
 | |
| 					"maximum": 65535,
 | |
| 					"format": "uc-portrange"
 | |
| 				}
 | |
| 			},
 | |
| 			"required": [
 | |
| 				"external-port",
 | |
| 				"internal-address"
 | |
| 			]
 | |
| 		},
 | |
| 		"interface.ipv6.traffic-allow": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"protocol": {
 | |
| 					"type": "string",
 | |
| 					"default": "any"
 | |
| 				},
 | |
| 				"source-address": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-cidr6",
 | |
| 					"example": "2001:db8:1234:abcd::/64",
 | |
| 					"default": "::/0"
 | |
| 				},
 | |
| 				"source-ports": {
 | |
| 					"type": "array",
 | |
| 					"minItems": 1,
 | |
| 					"items": {
 | |
| 						"type": [
 | |
| 							"integer",
 | |
| 							"string"
 | |
| 						],
 | |
| 						"minimum": 0,
 | |
| 						"maximum": 65535,
 | |
| 						"format": "uc-portrange"
 | |
| 					}
 | |
| 				},
 | |
| 				"destination-address": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv6",
 | |
| 					"example": "::1000"
 | |
| 				},
 | |
| 				"destination-ports": {
 | |
| 					"type": "array",
 | |
| 					"minItems": 1,
 | |
| 					"items": {
 | |
| 						"type": [
 | |
| 							"integer",
 | |
| 							"string"
 | |
| 						],
 | |
| 						"minimum": 0,
 | |
| 						"maximum": 65535,
 | |
| 						"format": "uc-portrange"
 | |
| 					}
 | |
| 				}
 | |
| 			},
 | |
| 			"required": [
 | |
| 				"destination-address"
 | |
| 			]
 | |
| 		},
 | |
| 		"interface.ipv6": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"addressing": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"dynamic",
 | |
| 						"static"
 | |
| 					]
 | |
| 				},
 | |
| 				"subnet": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-cidr6",
 | |
| 					"examples": [
 | |
| 						"auto/64"
 | |
| 					]
 | |
| 				},
 | |
| 				"gateway": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv6",
 | |
| 					"examples": [
 | |
| 						"2001:db8:123:456::1"
 | |
| 					]
 | |
| 				},
 | |
| 				"prefix-size": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 64,
 | |
| 					"minimum": 0
 | |
| 				},
 | |
| 				"dhcpv6": {
 | |
| 					"$ref": "#/$defs/interface.ipv6.dhcpv6"
 | |
| 				},
 | |
| 				"port-forward": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ipv6.port-forward"
 | |
| 					}
 | |
| 				},
 | |
| 				"traffic-allow": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ipv6.traffic-allow"
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.broad-band.wwan": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"protocol": {
 | |
| 					"type": "string",
 | |
| 					"const": "wwan"
 | |
| 				},
 | |
| 				"modem-type": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"qmi",
 | |
| 						"mbim",
 | |
| 						"wwan"
 | |
| 					]
 | |
| 				},
 | |
| 				"access-point-name": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"authentication-type": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"none",
 | |
| 						"pap",
 | |
| 						"chap",
 | |
| 						"pap-chap"
 | |
| 					],
 | |
| 					"default": "none"
 | |
| 				},
 | |
| 				"pin-code": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"user-name": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"password": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"packet-data-protocol": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"ipv4",
 | |
| 						"ipv6",
 | |
| 						"dual-stack"
 | |
| 					],
 | |
| 					"default": "dual-stack"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.broad-band.pppoe": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"protocol": {
 | |
| 					"type": "string",
 | |
| 					"const": "pppoe"
 | |
| 				},
 | |
| 				"user-name": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"password": {
 | |
| 					"type": "string"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.broad-band": {
 | |
| 			"oneOf": [{
 | |
| 					"$ref": "#/$defs/interface.broad-band.wwan"
 | |
| 				},
 | |
| 				{
 | |
| 					"$ref": "#/$defs/interface.broad-band.pppoe"
 | |
| 				}
 | |
| 			]
 | |
| 		},
 | |
| 		"interface.captive": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"gateway-name": {
 | |
| 					"type": "string",
 | |
| 					"default": "uCentral - Captive Portal"
 | |
| 				},
 | |
| 				"gateway-fqdn": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-fqdn",
 | |
| 					"default": "ucentral.splash"
 | |
| 				},
 | |
| 				"max-clients": {
 | |
| 					"type": "integer",
 | |
| 					"default": 32
 | |
| 				},
 | |
| 				"upload-rate": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"download-rate": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"upload-quota": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"download-quota": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.encryption": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"proto": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"none",
 | |
| 						"psk",
 | |
| 						"psk2",
 | |
| 						"psk-mixed",
 | |
| 						"psk2-radius",
 | |
| 						"wpa",
 | |
| 						"wpa2",
 | |
| 						"wpa-mixed",
 | |
| 						"sae",
 | |
| 						"sae-mixed",
 | |
| 						"wpa3",
 | |
| 						"wpa3-192",
 | |
| 						"wpa3-mixed"
 | |
| 					],
 | |
| 					"examples": [
 | |
| 						"psk2"
 | |
| 					]
 | |
| 				},
 | |
| 				"key": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 63,
 | |
| 					"minLength": 8
 | |
| 				},
 | |
| 				"ieee80211w": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"disabled",
 | |
| 						"optional",
 | |
| 						"required"
 | |
| 					],
 | |
| 					"default": "disabled"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.multi-psk": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"mac": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-mac"
 | |
| 				},
 | |
| 				"key": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 63,
 | |
| 					"minLength": 8
 | |
| 				},
 | |
| 				"vlan-id": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 4096,
 | |
| 					"examples": [
 | |
| 						3,
 | |
| 						100,
 | |
| 						200,
 | |
| 						4094
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.rrm": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"neighbor-reporting": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"reduced-neighbor-reporting": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"lci": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"civic-location": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"ftm-responder": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"stationary-ap": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.rate-limit": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"ingress-rate": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"egress-rate": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.roaming": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"message-exchange": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"air",
 | |
| 						"ds"
 | |
| 					],
 | |
| 					"default": "ds"
 | |
| 				},
 | |
| 				"generate-psk": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"domain-identifier": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 4,
 | |
| 					"minLength": 4,
 | |
| 					"examples": [
 | |
| 						"abcd"
 | |
| 					]
 | |
| 				},
 | |
| 				"pmk-r0-key-holder": {
 | |
| 					"type": "string",
 | |
| 					"example": "14:DD:20:47:14:E4,14DD204714E4,00112233445566778899aabbccddeeff"
 | |
| 				},
 | |
| 				"pmk-r1-key-holder": {
 | |
| 					"type": "string",
 | |
| 					"example": "14:DD:20:47:14:E4,14DD204714E4,00112233445566778899aabbccddeeff"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.radius.local-user": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"mac": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-mac"
 | |
| 				},
 | |
| 				"user-name": {
 | |
| 					"type": "string",
 | |
| 					"minLength": 1
 | |
| 				},
 | |
| 				"password": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 63,
 | |
| 					"minLength": 8
 | |
| 				},
 | |
| 				"vlan-id": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 4096,
 | |
| 					"examples": [
 | |
| 						3,
 | |
| 						100,
 | |
| 						200,
 | |
| 						4094
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.radius.local": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"server-identity": {
 | |
| 					"type": "string",
 | |
| 					"default": "uCentral"
 | |
| 				},
 | |
| 				"users": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ssid.radius.local-user"
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.radius.server": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"host": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-host",
 | |
| 					"examples": [
 | |
| 						"192.168.1.10"
 | |
| 					]
 | |
| 				},
 | |
| 				"port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 1024,
 | |
| 					"examples": [
 | |
| 						1812
 | |
| 					]
 | |
| 				},
 | |
| 				"secret": {
 | |
| 					"type": "string",
 | |
| 					"examples": [
 | |
| 						"secret"
 | |
| 					]
 | |
| 				},
 | |
| 				"request-attribute": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "object",
 | |
| 						"properties": {
 | |
| 							"id": {
 | |
| 								"type": "integer",
 | |
| 								"maximum": 255,
 | |
| 								"minimum": 1
 | |
| 							},
 | |
| 							"value": {
 | |
| 								"anyOf": [{
 | |
| 										"type": "integer",
 | |
| 										"maximum": 4294967295,
 | |
| 										"minimum": 0
 | |
| 									},
 | |
| 									{
 | |
| 										"type": "string"
 | |
| 									}
 | |
| 								]
 | |
| 							}
 | |
| 						},
 | |
| 						"examples": [{
 | |
| 								"id": 27,
 | |
| 								"value": 900
 | |
| 							},
 | |
| 							{
 | |
| 								"id": 32,
 | |
| 								"value": "My NAS ID"
 | |
| 							},
 | |
| 							{
 | |
| 								"id": 56,
 | |
| 								"value": 1004
 | |
| 							},
 | |
| 							{
 | |
| 								"id": 126,
 | |
| 								"value": "Example Operator"
 | |
| 							}
 | |
| 						]
 | |
| 					},
 | |
| 					"examples": [
 | |
| 						"126:s:Operator"
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.radius": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"nas-identifier": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"chargeable-user-id": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"local": {
 | |
| 					"$ref": "#/$defs/interface.ssid.radius.local"
 | |
| 				},
 | |
| 				"dynamic-authorization": {
 | |
| 					"type": "object",
 | |
| 					"properties": {
 | |
| 						"host": {
 | |
| 							"type": "string",
 | |
| 							"format": "uc-ip",
 | |
| 							"examples": [
 | |
| 								"192.168.1.10"
 | |
| 							]
 | |
| 						},
 | |
| 						"port": {
 | |
| 							"type": "integer",
 | |
| 							"maximum": 65535,
 | |
| 							"minimum": 1024,
 | |
| 							"examples": [
 | |
| 								1812
 | |
| 							]
 | |
| 						},
 | |
| 						"secret": {
 | |
| 							"type": "string",
 | |
| 							"examples": [
 | |
| 								"secret"
 | |
| 							]
 | |
| 						}
 | |
| 					}
 | |
| 				},
 | |
| 				"authentication": {
 | |
| 					"allOf": [{
 | |
| 							"$ref": "#/$defs/interface.ssid.radius.server"
 | |
| 						},
 | |
| 						{
 | |
| 							"type": "object",
 | |
| 							"properties": {
 | |
| 								"mac-filter": {
 | |
| 									"type": "boolean",
 | |
| 									"default": false
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					]
 | |
| 				},
 | |
| 				"accounting": {
 | |
| 					"allOf": [{
 | |
| 							"$ref": "#/$defs/interface.ssid.radius.server"
 | |
| 						},
 | |
| 						{
 | |
| 							"type": "object",
 | |
| 							"properties": {
 | |
| 								"interval": {
 | |
| 									"type": "integer",
 | |
| 									"maximum": 600,
 | |
| 									"minimum": 60,
 | |
| 									"default": 60
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.certificates": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"use-local-certificates": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"ca-certificate": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"certificate": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"private-key": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"private-key-password": {
 | |
| 					"type": "string"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.pass-point": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"venue-name": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string"
 | |
| 					}
 | |
| 				},
 | |
| 				"venue-group": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 32
 | |
| 				},
 | |
| 				"venue-type": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 32
 | |
| 				},
 | |
| 				"venue-url": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"format": "uri"
 | |
| 					}
 | |
| 				},
 | |
| 				"auth-type": {
 | |
| 					"type": "object",
 | |
| 					"properties": {
 | |
| 						"type": {
 | |
| 							"type": "string",
 | |
| 							"enum": [
 | |
| 								"terms-and-conditions",
 | |
| 								"online-enrollment",
 | |
| 								"http-redirection",
 | |
| 								"dns-redirection"
 | |
| 							]
 | |
| 						},
 | |
| 						"uri": {
 | |
| 							"type": "string",
 | |
| 							"format": "uri",
 | |
| 							"examples": [
 | |
| 								"https://operator.example.org/wireless-access/terms-and-conditions.html",
 | |
| 								"http://www.example.com/redirect/me/here/"
 | |
| 							]
 | |
| 						}
 | |
| 					},
 | |
| 					"minLength": 2,
 | |
| 					"maxLength": 2
 | |
| 				},
 | |
| 				"domain-name": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"format": "hostname"
 | |
| 					}
 | |
| 				},
 | |
| 				"nai-realm": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string"
 | |
| 					}
 | |
| 				},
 | |
| 				"osen": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"anqp-domain": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 0
 | |
| 				},
 | |
| 				"anqp-3gpp-cell-net": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string"
 | |
| 					}
 | |
| 				},
 | |
| 				"friendly-name": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string"
 | |
| 					}
 | |
| 				},
 | |
| 				"access-network-type": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 15,
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"internet": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				},
 | |
| 				"asra": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"esr": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"uesa": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"hessid": {
 | |
| 					"type": "string",
 | |
| 					"example": "00:11:22:33:44:55"
 | |
| 				},
 | |
| 				"roaming-consortium": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string"
 | |
| 					}
 | |
| 				},
 | |
| 				"disable-dgaf": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"ipaddr-type-available": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 255
 | |
| 				},
 | |
| 				"connection-capability": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string"
 | |
| 					}
 | |
| 				},
 | |
| 				"icons": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "object",
 | |
| 						"properties": {
 | |
| 							"width": {
 | |
| 								"type": "integer",
 | |
| 								"examples": [
 | |
| 									64
 | |
| 								]
 | |
| 							},
 | |
| 							"height": {
 | |
| 								"type": "integer",
 | |
| 								"examples": [
 | |
| 									64
 | |
| 								]
 | |
| 							},
 | |
| 							"type": {
 | |
| 								"type": "string",
 | |
| 								"examples": [
 | |
| 									"image/png"
 | |
| 								]
 | |
| 							},
 | |
| 							"icon": {
 | |
| 								"type": "string",
 | |
| 								"format": "uc-base64"
 | |
| 							},
 | |
| 							"language": {
 | |
| 								"type": "string",
 | |
| 								"pattern": "^[a-z][a-z][a-z]$",
 | |
| 								"examples": [
 | |
| 									"eng",
 | |
| 									"fre",
 | |
| 									"ger",
 | |
| 									"ita"
 | |
| 								]
 | |
| 							}
 | |
| 						},
 | |
| 						"examples": [{
 | |
| 							"width": 32,
 | |
| 							"height": 32,
 | |
| 							"type": "image/png",
 | |
| 							"language": "eng",
 | |
| 							"icon": "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
 | |
| 						}]
 | |
| 					}
 | |
| 				},
 | |
| 				"wan-metrics": {
 | |
| 					"type": "object",
 | |
| 					"properties": {
 | |
| 						"info": {
 | |
| 							"type": "string",
 | |
| 							"enum": [
 | |
| 								"up",
 | |
| 								"down",
 | |
| 								"testing"
 | |
| 							]
 | |
| 						},
 | |
| 						"downlink": {
 | |
| 							"type": "integer"
 | |
| 						},
 | |
| 						"uplink": {
 | |
| 							"type": "integer"
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid.quality-thresholds": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"probe-request-rssi": {
 | |
| 					"type": "integer"
 | |
| 				},
 | |
| 				"association-request-rssi": {
 | |
| 					"type": "integer"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.ssid": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"purpose": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"user-defined",
 | |
| 						"onboarding-ap",
 | |
| 						"onboarding-sta"
 | |
| 					],
 | |
| 					"default": "user-defined"
 | |
| 				},
 | |
| 				"name": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 32,
 | |
| 					"minLength": 1
 | |
| 				},
 | |
| 				"wifi-bands": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"enum": [
 | |
| 							"2G",
 | |
| 							"5G",
 | |
| 							"5G-lower",
 | |
| 							"5G-upper",
 | |
| 							"6G"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"bss-mode": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"ap",
 | |
| 						"sta",
 | |
| 						"mesh",
 | |
| 						"wds-ap",
 | |
| 						"wds-sta",
 | |
| 						"wds-repeater"
 | |
| 					],
 | |
| 					"default": "ap"
 | |
| 				},
 | |
| 				"bssid": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-mac"
 | |
| 				},
 | |
| 				"hidden-ssid": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"isolate-clients": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"power-save": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"rts-threshold": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 1
 | |
| 				},
 | |
| 				"broadcast-time": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"unicast-conversion": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"services": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"wifi-steering"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"maximum-clients": {
 | |
| 					"type": "integer",
 | |
| 					"example": 64
 | |
| 				},
 | |
| 				"proxy-arp": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				},
 | |
| 				"disassoc-low-ack": {
 | |
| 					"decription": "Disassociate stations based on excessive transmission failures or other indications of connection loss.",
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"vendor-elements": {
 | |
| 					"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.",
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"fils-discovery-interval": {
 | |
| 					"type": "integer",
 | |
| 					"default": 20,
 | |
| 					"maximum": 10000
 | |
| 				},
 | |
| 				"encryption": {
 | |
| 					"$ref": "#/$defs/interface.ssid.encryption"
 | |
| 				},
 | |
| 				"multi-psk": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ssid.multi-psk"
 | |
| 					}
 | |
| 				},
 | |
| 				"rrm": {
 | |
| 					"$ref": "#/$defs/interface.ssid.rrm"
 | |
| 				},
 | |
| 				"rate-limit": {
 | |
| 					"$ref": "#/$defs/interface.ssid.rate-limit"
 | |
| 				},
 | |
| 				"roaming": {
 | |
| 					"$ref": "#/$defs/interface.ssid.roaming"
 | |
| 				},
 | |
| 				"radius": {
 | |
| 					"$ref": "#/$defs/interface.ssid.radius"
 | |
| 				},
 | |
| 				"certificates": {
 | |
| 					"$ref": "#/$defs/interface.ssid.certificates"
 | |
| 				},
 | |
| 				"pass-point": {
 | |
| 					"$ref": "#/$defs/interface.ssid.pass-point"
 | |
| 				},
 | |
| 				"quality-thresholds": {
 | |
| 					"$ref": "#/$defs/interface.ssid.quality-thresholds"
 | |
| 				},
 | |
| 				"hostapd-bss-raw": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"ap_table_expiration_time=3600",
 | |
| 							"device_type=6-0050F204-1",
 | |
| 							"ieee80211h=1",
 | |
| 							"rssi_ignore_probe_request=-75",
 | |
| 							"time_zone=EST5",
 | |
| 							"uuid=12345678-9abc-def0-1234-56789abcdef0",
 | |
| 							"venue_url=1:http://www.example.com/info-eng",
 | |
| 							"wpa_deny_ptk0_rekey=0"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.tunnel.mesh": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"proto": {
 | |
| 					"type": "string",
 | |
| 					"const": "mesh"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.tunnel.vxlan": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"proto": {
 | |
| 					"type": "string",
 | |
| 					"const": "vxlan"
 | |
| 				},
 | |
| 				"peer-address": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv4",
 | |
| 					"example": "192.168.100.1"
 | |
| 				},
 | |
| 				"peer-port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 1,
 | |
| 					"examples": [
 | |
| 						4789
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.tunnel.l2tp": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"proto": {
 | |
| 					"type": "string",
 | |
| 					"const": "l2tp"
 | |
| 				},
 | |
| 				"server": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv4",
 | |
| 					"example": "192.168.100.1"
 | |
| 				},
 | |
| 				"user-name": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"password": {
 | |
| 					"type": "string"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.tunnel.gre": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"proto": {
 | |
| 					"type": "string",
 | |
| 					"const": "gre"
 | |
| 				},
 | |
| 				"peer-address": {
 | |
| 					"type": "string",
 | |
| 					"format": "ipv4",
 | |
| 					"example": "192.168.100.1"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"interface.tunnel": {
 | |
| 			"oneOf": [{
 | |
| 					"$ref": "#/$defs/interface.tunnel.mesh"
 | |
| 				},
 | |
| 				{
 | |
| 					"$ref": "#/$defs/interface.tunnel.vxlan"
 | |
| 				},
 | |
| 				{
 | |
| 					"$ref": "#/$defs/interface.tunnel.l2tp"
 | |
| 				},
 | |
| 				{
 | |
| 					"$ref": "#/$defs/interface.tunnel.gre"
 | |
| 				}
 | |
| 			]
 | |
| 		},
 | |
| 		"interface": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"name": {
 | |
| 					"type": "string",
 | |
| 					"examples": [
 | |
| 						"LAN"
 | |
| 					]
 | |
| 				},
 | |
| 				"role": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"upstream",
 | |
| 						"downstream"
 | |
| 					]
 | |
| 				},
 | |
| 				"isolate-hosts": {
 | |
| 					"type": "boolean"
 | |
| 				},
 | |
| 				"metric": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 4294967295,
 | |
| 					"minimum": 0
 | |
| 				},
 | |
| 				"services": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"ssh",
 | |
| 							"lldp"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"vlan": {
 | |
| 					"$ref": "#/$defs/interface.vlan"
 | |
| 				},
 | |
| 				"bridge": {
 | |
| 					"$ref": "#/$defs/interface.bridge"
 | |
| 				},
 | |
| 				"ethernet": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ethernet"
 | |
| 					}
 | |
| 				},
 | |
| 				"ipv4": {
 | |
| 					"$ref": "#/$defs/interface.ipv4"
 | |
| 				},
 | |
| 				"ipv6": {
 | |
| 					"$ref": "#/$defs/interface.ipv6"
 | |
| 				},
 | |
| 				"broad-band": {
 | |
| 					"$ref": "#/$defs/interface.broad-band"
 | |
| 				},
 | |
| 				"captive": {
 | |
| 					"$ref": "#/$defs/interface.captive"
 | |
| 				},
 | |
| 				"ssids": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ssid"
 | |
| 					}
 | |
| 				},
 | |
| 				"tunnel": {
 | |
| 					"$ref": "#/$defs/interface.tunnel"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.lldp": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"describe": {
 | |
| 					"type": "string",
 | |
| 					"default": "uCentral Access Point"
 | |
| 				},
 | |
| 				"location": {
 | |
| 					"type": "string",
 | |
| 					"default": "uCentral Network"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.ssh": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"default": 22
 | |
| 				},
 | |
| 				"authorized-keys": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC0ghdSd2D2y08TFowZLMZn3x1/Djw3BkNsIeHt/Z+RaXwvfV1NQAnNdaOngMT/3uf5jZtYxhpl+dbZtRhoUPRvKflKBeFHYBqjZVzD3r4ns2Ofm2UpHlbdOpMuy9oeTSCeF0IKZZ6szpkvSirQogeP2fe9KRkzQpiza6YxxaJlWw== user@example",
 | |
| 							"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ4FDjyCsg+1Mh2C5G7ibR3z0Kw1dU57kfXebLRwS6CL bob@work",
 | |
| 							"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP/JpJ/KHtKKImzISBDwLO0/EwytIr4pGZQXcP6GCSHchLMyfjf147KNlF9gC+3FibzqKH02EiQspVhRgfuK6y0= alice@home"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"password-authentication": {
 | |
| 					"type": "boolean",
 | |
| 					"default": true
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.ntp": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"servers": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"format": "uc-host"
 | |
| 					},
 | |
| 					"examples": [
 | |
| 						"0.openwrt.pool.ntp.org"
 | |
| 					]
 | |
| 				},
 | |
| 				"local-server": {
 | |
| 					"type": "boolean",
 | |
| 					"examples": [
 | |
| 						true
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.mdns": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"enable": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.rtty": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"host": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-host",
 | |
| 					"examples": [
 | |
| 						"192.168.1.10"
 | |
| 					]
 | |
| 				},
 | |
| 				"port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"default": 5912
 | |
| 				},
 | |
| 				"token": {
 | |
| 					"type": "string",
 | |
| 					"maxLength": 32,
 | |
| 					"minLength": 32,
 | |
| 					"examples": [
 | |
| 						"01234567890123456789012345678901"
 | |
| 					]
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.log": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"host": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-host",
 | |
| 					"examples": [
 | |
| 						"192.168.1.10"
 | |
| 					]
 | |
| 				},
 | |
| 				"port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 100,
 | |
| 					"examples": [
 | |
| 						2000
 | |
| 					]
 | |
| 				},
 | |
| 				"proto": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"tcp",
 | |
| 						"udp"
 | |
| 					],
 | |
| 					"default": "udp"
 | |
| 				},
 | |
| 				"size": {
 | |
| 					"type": "integer",
 | |
| 					"minimum": 32,
 | |
| 					"default": 1000
 | |
| 				},
 | |
| 				"priority": {
 | |
| 					"type": "integer",
 | |
| 					"minimum": 0,
 | |
| 					"default": 7
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.http": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"http-port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"minimum": 1,
 | |
| 					"default": 80
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.igmp": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"enable": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.ieee8021x": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"ca-certificate": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"use-local-certificates": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"server-certificate": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"private-key": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"users": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"$ref": "#/$defs/interface.ssid.radius.local-user"
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.radius-proxy": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"realms": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "object",
 | |
| 						"properties": {
 | |
| 							"realm": {
 | |
| 								"type": "string",
 | |
| 								"default": "*"
 | |
| 							},
 | |
| 							"auto-discover": {
 | |
| 								"type": "boolean",
 | |
| 								"default": false
 | |
| 							},
 | |
| 							"host": {
 | |
| 								"type": "string",
 | |
| 								"format": "uc-host",
 | |
| 								"examples": [
 | |
| 									"192.168.1.10"
 | |
| 								]
 | |
| 							},
 | |
| 							"port": {
 | |
| 								"type": "integer",
 | |
| 								"maximum": 65535,
 | |
| 								"default": 2083
 | |
| 							},
 | |
| 							"secret": {
 | |
| 								"type": "string"
 | |
| 							},
 | |
| 							"use-local-certificates": {
 | |
| 								"type": "boolean",
 | |
| 								"default": false
 | |
| 							},
 | |
| 							"ca-certificate": {
 | |
| 								"type": "string"
 | |
| 							},
 | |
| 							"certificate": {
 | |
| 								"type": "string"
 | |
| 							},
 | |
| 							"private-key": {
 | |
| 								"type": "string"
 | |
| 							},
 | |
| 							"private-key-password": {
 | |
| 								"type": "string"
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.online-check": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"ping-hosts": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"format": "uc-host",
 | |
| 						"examples": [
 | |
| 							"192.168.1.10"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"download-hosts": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"examples": [
 | |
| 							"www.example.org"
 | |
| 						]
 | |
| 					}
 | |
| 				},
 | |
| 				"check-interval": {
 | |
| 					"type": "number",
 | |
| 					"default": 60
 | |
| 				},
 | |
| 				"check-threshold": {
 | |
| 					"type": "number",
 | |
| 					"default": 1
 | |
| 				},
 | |
| 				"action": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"enum": [
 | |
| 							"wifi",
 | |
| 							"leds"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.open-flow": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"controller": {
 | |
| 					"type": "string",
 | |
| 					"format": "uc-ip",
 | |
| 					"example": "192.168.10.1"
 | |
| 				},
 | |
| 				"datapath-description": {
 | |
| 					"type": "string",
 | |
| 					"example": "Building 2, Floor 6, AP 2"
 | |
| 				},
 | |
| 				"mode": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"pssl",
 | |
| 						"ptcp",
 | |
| 						"ssl",
 | |
| 						"tcp"
 | |
| 					],
 | |
| 					"default": "ssl"
 | |
| 				},
 | |
| 				"port": {
 | |
| 					"type": "integer",
 | |
| 					"maximum": 65535,
 | |
| 					"default": 6653
 | |
| 				},
 | |
| 				"ca-certificate": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"ssl-certificate": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"private-key": {
 | |
| 					"type": "string"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.data-plane": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"ingress-filters": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "object",
 | |
| 						"properties": {
 | |
| 							"name": {
 | |
| 								"type": "string"
 | |
| 							},
 | |
| 							"program": {
 | |
| 								"type": "string",
 | |
| 								"format": "uc-base64"
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.wifi-steering": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"mode": {
 | |
| 					"type": "string",
 | |
| 					"enum": [
 | |
| 						"local",
 | |
| 						"cloud"
 | |
| 					],
 | |
| 					"examples": [
 | |
| 						"local"
 | |
| 					]
 | |
| 				},
 | |
| 				"assoc-steering": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"required-snr": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"required-probe-snr": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"required-roam-snr": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"load-kick-threshold": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"auto-channel": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				},
 | |
| 				"ipv6": {
 | |
| 					"type": "boolean",
 | |
| 					"default": false
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.quality-of-service.class-selector": {
 | |
| 			"type": "string",
 | |
| 			"enum": [
 | |
| 				"CS0",
 | |
| 				"CS1",
 | |
| 				"CS2",
 | |
| 				"CS3",
 | |
| 				"CS4",
 | |
| 				"CS5",
 | |
| 				"CS6",
 | |
| 				"CS7",
 | |
| 				"AF11",
 | |
| 				"AF12",
 | |
| 				"AF13",
 | |
| 				"AF21",
 | |
| 				"AF22",
 | |
| 				"AF23",
 | |
| 				"AF31",
 | |
| 				"AF32",
 | |
| 				"AF33",
 | |
| 				"AF41",
 | |
| 				"AF42",
 | |
| 				"AF43",
 | |
| 				"DF",
 | |
| 				"EF",
 | |
| 				"VA",
 | |
| 				"LE"
 | |
| 			]
 | |
| 		},
 | |
| 		"service.quality-of-service": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"select-ports": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"default": "WAN"
 | |
| 					}
 | |
| 				},
 | |
| 				"bandwidth-up": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"bandwidth-down": {
 | |
| 					"type": "integer",
 | |
| 					"default": 0
 | |
| 				},
 | |
| 				"bulk-detection": {
 | |
| 					"type": "object",
 | |
| 					"properties": {
 | |
| 						"dscp": {
 | |
| 							"$ref": "#/$defs/service.quality-of-service.class-selector",
 | |
| 							"default": "CS0"
 | |
| 						},
 | |
| 						"packets-per-second": {
 | |
| 							"type": "number",
 | |
| 							"default": 0
 | |
| 						}
 | |
| 					}
 | |
| 				},
 | |
| 				"classifier": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "object",
 | |
| 						"properties": {
 | |
| 							"dscp": {
 | |
| 								"$ref": "#/$defs/service.quality-of-service.class-selector",
 | |
| 								"default": "CS1"
 | |
| 							},
 | |
| 							"ports": {
 | |
| 								"type": "array",
 | |
| 								"items": {
 | |
| 									"type": "object",
 | |
| 									"properties": {
 | |
| 										"protocol": {
 | |
| 											"type": "string",
 | |
| 											"enum": [
 | |
| 												"any",
 | |
| 												"tcp",
 | |
| 												"udp"
 | |
| 											],
 | |
| 											"default": "any"
 | |
| 										},
 | |
| 										"port": {
 | |
| 											"type": "integer"
 | |
| 										},
 | |
| 										"range-end": {
 | |
| 											"type": "integer"
 | |
| 										},
 | |
| 										"reclassify": {
 | |
| 											"type": "boolean",
 | |
| 											"default": true
 | |
| 										}
 | |
| 									}
 | |
| 								}
 | |
| 							},
 | |
| 							"dns": {
 | |
| 								"type": "array",
 | |
| 								"items": {
 | |
| 									"type": "object",
 | |
| 									"properties": {
 | |
| 										"fqdn": {
 | |
| 											"type": "string",
 | |
| 											"format": "uc-fqdn"
 | |
| 										},
 | |
| 										"suffix-matching": {
 | |
| 											"type": "boolean",
 | |
| 											"default": true
 | |
| 										},
 | |
| 										"reclassify": {
 | |
| 											"type": "boolean",
 | |
| 											"default": true
 | |
| 										}
 | |
| 									}
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.facebook-wifi": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"vendor-id": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"gateway-id": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"secret": {
 | |
| 					"type": "string"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service.airtime-fairness": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"voice-weight": {
 | |
| 					"type": "number",
 | |
| 					"default": 4
 | |
| 				},
 | |
| 				"packet-threshold": {
 | |
| 					"type": "number",
 | |
| 					"default": 100
 | |
| 				},
 | |
| 				"bulk-threshold": {
 | |
| 					"type": "number",
 | |
| 					"default": 50
 | |
| 				},
 | |
| 				"priority-threshold": {
 | |
| 					"type": "number",
 | |
| 					"default": 30
 | |
| 				},
 | |
| 				"weight-normal": {
 | |
| 					"type": "number",
 | |
| 					"default": 256
 | |
| 				},
 | |
| 				"weight-priority": {
 | |
| 					"type": "number",
 | |
| 					"default": 394
 | |
| 				},
 | |
| 				"weight-bulk": {
 | |
| 					"type": "number",
 | |
| 					"default": 128
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"service": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"lldp": {
 | |
| 					"$ref": "#/$defs/service.lldp"
 | |
| 				},
 | |
| 				"ssh": {
 | |
| 					"$ref": "#/$defs/service.ssh"
 | |
| 				},
 | |
| 				"ntp": {
 | |
| 					"$ref": "#/$defs/service.ntp"
 | |
| 				},
 | |
| 				"mdns": {
 | |
| 					"$ref": "#/$defs/service.mdns"
 | |
| 				},
 | |
| 				"rtty": {
 | |
| 					"$ref": "#/$defs/service.rtty"
 | |
| 				},
 | |
| 				"log": {
 | |
| 					"$ref": "#/$defs/service.log"
 | |
| 				},
 | |
| 				"http": {
 | |
| 					"$ref": "#/$defs/service.http"
 | |
| 				},
 | |
| 				"igmp": {
 | |
| 					"$ref": "#/$defs/service.igmp"
 | |
| 				},
 | |
| 				"ieee8021x": {
 | |
| 					"$ref": "#/$defs/service.ieee8021x"
 | |
| 				},
 | |
| 				"radius-proxy": {
 | |
| 					"$ref": "#/$defs/service.radius-proxy"
 | |
| 				},
 | |
| 				"online-check": {
 | |
| 					"$ref": "#/$defs/service.online-check"
 | |
| 				},
 | |
| 				"open-flow": {
 | |
| 					"$ref": "#/$defs/service.open-flow"
 | |
| 				},
 | |
| 				"data-plane": {
 | |
| 					"$ref": "#/$defs/service.data-plane"
 | |
| 				},
 | |
| 				"wifi-steering": {
 | |
| 					"$ref": "#/$defs/service.wifi-steering"
 | |
| 				},
 | |
| 				"quality-of-service": {
 | |
| 					"$ref": "#/$defs/service.quality-of-service"
 | |
| 				},
 | |
| 				"facebook-wifi": {
 | |
| 					"$ref": "#/$defs/service.facebook-wifi"
 | |
| 				},
 | |
| 				"airtime-fairness": {
 | |
| 					"$ref": "#/$defs/service.airtime-fairness"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"metrics.statistics": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"interval": {
 | |
| 					"type": "integer"
 | |
| 				},
 | |
| 				"types": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"enum": [
 | |
| 							"ssids",
 | |
| 							"lldp",
 | |
| 							"clients"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"metrics.health": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"interval": {
 | |
| 					"type": "integer",
 | |
| 					"minimum": 60
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"metrics.wifi-frames": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"filters": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"enum": [
 | |
| 							"probe",
 | |
| 							"auth",
 | |
| 							"assoc",
 | |
| 							"disassoc",
 | |
| 							"deauth",
 | |
| 							"local-deauth",
 | |
| 							"inactive-deauth",
 | |
| 							"key-mismatch",
 | |
| 							"beacon-report",
 | |
| 							"radar-detected"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"metrics.dhcp-snooping": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"filters": {
 | |
| 					"type": "array",
 | |
| 					"items": {
 | |
| 						"type": "string",
 | |
| 						"enum": [
 | |
| 							"ack",
 | |
| 							"discover",
 | |
| 							"offer",
 | |
| 							"request",
 | |
| 							"solicit",
 | |
| 							"reply",
 | |
| 							"renew"
 | |
| 						]
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"metrics": {
 | |
| 			"type": "object",
 | |
| 			"properties": {
 | |
| 				"statistics": {
 | |
| 					"$ref": "#/$defs/metrics.statistics"
 | |
| 				},
 | |
| 				"health": {
 | |
| 					"$ref": "#/$defs/metrics.health"
 | |
| 				},
 | |
| 				"wifi-frames": {
 | |
| 					"$ref": "#/$defs/metrics.wifi-frames"
 | |
| 				},
 | |
| 				"dhcp-snooping": {
 | |
| 					"$ref": "#/$defs/metrics.dhcp-snooping"
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 		"config-raw": {
 | |
| 			"type": "array",
 | |
| 			"items": {
 | |
| 				"type": "array",
 | |
| 				"minItems": 2,
 | |
| 				"items": {
 | |
| 					"type": "string"
 | |
| 				},
 | |
| 				"examples": [
 | |
| 					[
 | |
| 						"set",
 | |
| 						"system.@system[0].timezone",
 | |
| 						"GMT0"
 | |
| 					],
 | |
| 					[
 | |
| 						"delete",
 | |
| 						"firewall.@zone[0]"
 | |
| 					],
 | |
| 					[
 | |
| 						"delete",
 | |
| 						"dhcp.wan"
 | |
| 					],
 | |
| 					[
 | |
| 						"add",
 | |
| 						"dhcp",
 | |
| 						"dhcp"
 | |
| 					],
 | |
| 					[
 | |
| 						"add-list",
 | |
| 						"system.ntp.server",
 | |
| 						"0.pool.example.org"
 | |
| 					],
 | |
| 					[
 | |
| 						"del-list",
 | |
| 						"system.ntp.server",
 | |
| 						"1.openwrt.pool.ntp.org"
 | |
| 					]
 | |
| 				]
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| )"_json;
 | |
| 
 | |
|     class custom_error_handler : public nlohmann::json_schema::basic_error_handler
 | |
|     {
 | |
|         void error(const nlohmann::json_pointer<nlohmann::basic_json<>> &pointer, const json &instance,
 | |
|                    const std::string &message) override
 | |
|         {
 | |
|             nlohmann::json_schema::basic_error_handler::error(pointer, instance, message);
 | |
|             std::cout << "ERROR: '" << pointer << "' - '" << instance << "': " << message << "\n";
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     void ConfigurationValidator::Init() {
 | |
|         if(Initialized_)
 | |
|             return;
 | |
| 
 | |
|         std::string GitSchema;
 | |
| 		if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) {
 | |
| 			RootSchema_ = DefaultUCentralSchema;
 | |
| 			Logger().information("Using uCentral validation from built-in default.");
 | |
| 			Initialized_ = Working_ = true;
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
|         try {
 | |
| 			auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile);
 | |
|             if(Utils::wgets(GitURI, GitSchema)) {
 | |
|                 RootSchema_ = json::parse(GitSchema);
 | |
|                 Logger().information("Using uCentral validation schema from GIT.");
 | |
|             } else {
 | |
|                 std::string FileName{ MicroService::instance().DataDir() + "/ucentral.schema.json" };
 | |
|                 std::ifstream       input(FileName);
 | |
|                 std::stringstream   schema_file;
 | |
|                 schema_file << input.rdbuf();
 | |
|                 input.close();
 | |
|                 RootSchema_ = json::parse(schema_file.str());
 | |
|                 Logger().information("Using uCentral validation schema from local file.");
 | |
|             }
 | |
|         } catch (const Poco::Exception &E) {
 | |
|             RootSchema_ = DefaultUCentralSchema;
 | |
|             Logger().information("Using uCentral validation from built-in default.");
 | |
|         }
 | |
|         Initialized_ = Working_ = true;
 | |
|     }
 | |
| 
 | |
|     int ConfigurationValidator::Start() {
 | |
|         Init();
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     void ConfigurationValidator::Stop() {
 | |
| 
 | |
|     }
 | |
| 
 | |
|     static inline bool IsIPv4(const std::string &value) {
 | |
|         Poco::Net::IPAddress    A;
 | |
|         return ((Poco::Net::IPAddress::tryParse(value,A) && A.family()==Poco::Net::IPAddress::IPv4));
 | |
|     }
 | |
| 
 | |
|     static inline bool IsIPv6(const std::string &value) {
 | |
|         Poco::Net::IPAddress    A;
 | |
|         return ((Poco::Net::IPAddress::tryParse(value,A) && A.family()==Poco::Net::IPAddress::IPv6));
 | |
|     }
 | |
| 
 | |
|     static inline bool IsIP(const std::string &value) {
 | |
|         return IsIPv4(value) || IsIPv6(value);
 | |
|     }
 | |
| 
 | |
|     static inline bool IsCIDRv6(const std::string &value) {
 | |
|         auto Tokens = Poco::StringTokenizer(value,"/");
 | |
|         if(Tokens.count()==2 && IsIPv6(Tokens[0])) {
 | |
|             auto Mask = std::atoi(Tokens[1].c_str());
 | |
|             if(Mask>=48 && Mask<=128)
 | |
|                 return true;
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     static inline bool IsCIDRv4(const std::string &value) {
 | |
|         auto Tokens = Poco::StringTokenizer(value,"/");
 | |
|         if(Tokens.count()==2 && IsIPv4(Tokens[0])) {
 | |
|             auto Mask = std::atoi(Tokens[1].c_str());
 | |
|             if(Mask>=0 && Mask<=32)
 | |
|                 return true;
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     static inline bool IsCIDR(const std::string &value) {
 | |
|         return IsCIDRv4(value) || IsCIDRv6(value);
 | |
|     }
 | |
| 
 | |
|     static inline bool IsPortRangeIsValid(const std::string &r) {
 | |
|         const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM);
 | |
| 
 | |
|         for(const auto &port:ports) {
 | |
|             uint32_t port_num = std::stoul(port);
 | |
|             if(port_num==0 || port_num>65535)
 | |
|                 return false;
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value)
 | |
|     {
 | |
|         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"};
 | |
|         static const std::regex mac_regex{"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"};
 | |
|         static const std::regex uc_timeout_regex{"^[0-9]+[dmshw]$"};
 | |
|         static const std::regex b64_regex("^[a-zA-Z0-9\\+/]*={0,3}$");
 | |
| 
 | |
|         if(format == "uc-cidr4") {
 | |
|             if(IsCIDRv4(value))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a valid CIDR IPv4: should be something like 192.168.0.0/16.");
 | |
|         } else if(format == "uc-cidr6") {
 | |
|             if(IsCIDRv6(value))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a valid CIDR IPv6: should be something like 2e60:3500::/64.");
 | |
|         } else if(format=="uc-cidr") {
 | |
|             if(IsCIDR(value))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a valid CIDR IPv6/IPv4: should be something like 2e60:3500::/64.");
 | |
|         } else if(format == "uc-mac") {
 | |
|             if(std::regex_match(value,mac_regex))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a valid MAC: should be something like 11:22:33:44:55:66");
 | |
|         } else if(format == "uc-timeout") {
 | |
|             if(std::regex_match(value,uc_timeout_regex))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a proper timeout value: 6d, 300m, 24h, 84000s, infinite");
 | |
|         } else if(format == "uc-host") {
 | |
|             if(IsIP(value))
 | |
|                 return;
 | |
|             if(std::regex_match(value,host_regex))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a proper FQDN.");
 | |
|         } else if(format == "fqdn") {
 | |
|             if(std::regex_match(value,host_regex))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a proper FQDN.");
 | |
|         } else if(format == "uc-base64") {
 | |
|             std::string s{value};
 | |
|             Poco::trimInPlace(s);
 | |
|             if( (s.size() %4 ==0) && std::regex_match(s,b64_regex))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a base64 encoded value.");
 | |
|         } else if(format == "uri") {
 | |
|             try {
 | |
|                 Poco::URI   uri(value);
 | |
|                 return;
 | |
|             } catch (...) {
 | |
|             }
 | |
|             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com.");
 | |
|         } else if(format == "uc-portrange") {
 | |
|             try {
 | |
|                 if(IsPortRangeIsValid(value))
 | |
|                     return;
 | |
|                 throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port.");
 | |
|             } catch (...) {
 | |
|             }
 | |
|             throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port.");
 | |
|         } else if(format == "ip") {
 | |
|             if (IsIP(value))
 | |
|                 return;
 | |
|             throw std::invalid_argument(value + " is not a valid IP address.");
 | |
|         } else {
 | |
|             nlohmann::json_schema::default_string_format_check(format,value);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     bool ConfigurationValidator::Validate(const std::string &C, std::string &Error) {
 | |
|         if(Working_) {
 | |
|             try {
 | |
|                 auto Doc = json::parse(C);
 | |
|                 custom_error_handler CE;
 | |
|                 json_validator  Validator(nullptr, my_format_checker);
 | |
|                 Validator.set_root_schema(RootSchema_);
 | |
|                 Validator.validate(Doc,CE);
 | |
|                 return true;
 | |
|             } catch (const std::invalid_argument &E) {
 | |
|                 std::cout << "1 Validation failed, here is why: " << E.what() << "\n";
 | |
|                 Error = E.what();
 | |
|                 return false;
 | |
|             } catch (const std::logic_error &E) {
 | |
|                 std::cout << "2 Validation failed, here is why: " << E.what() << "\n";
 | |
|                 Error = E.what();
 | |
|                 return false;
 | |
|             } catch(const std::exception &E) {
 | |
|                 Error = E.what();
 | |
|                 std::cout << "3 Validation failed, here is why: " << E.what() << "\n";
 | |
|                 return false;
 | |
|             } catch(...) {
 | |
|                 std::cout << "4 Some kind of bullshit exception..." << std::endl;
 | |
|             }
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     void ConfigurationValidator::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
 | |
|         Logger().information("Reinitializing.");
 | |
|         Working_ = Initialized_ = false;
 | |
|         Init();
 | |
|     }
 | |
| 
 | |
| }
 | 
