mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
fixes
This commit is contained in:
@@ -34,7 +34,13 @@ import { TuiForm } from '@taiga-ui/layout'
|
||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { ApiService } from 'src/app/services/api/api.service'
|
||||
|
||||
import { getIp, DeviceData, MappedSubnet, subnetValidator } from './utils'
|
||||
import {
|
||||
getIp,
|
||||
DeviceData,
|
||||
MappedSubnet,
|
||||
subnetValidator,
|
||||
ipInSubnetValidator,
|
||||
} from './utils'
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
@@ -132,6 +138,11 @@ export class DevicesAdd {
|
||||
range ? `${name} (${range})` : ''
|
||||
|
||||
protected onSubnet(subnet: MappedSubnet) {
|
||||
this.form.controls.ip.clearValidators()
|
||||
this.form.controls.ip.addValidators([
|
||||
Validators.required,
|
||||
ipInSubnetValidator(subnet.range),
|
||||
])
|
||||
const ip = getIp(subnet)
|
||||
|
||||
if (ip) {
|
||||
|
||||
@@ -30,25 +30,31 @@ export function subnetValidator({ value }: AbstractControl<MappedSubnet>) {
|
||||
: { noHosts: 'No hosts available' }
|
||||
}
|
||||
|
||||
export function getIp({ clients, range }: MappedSubnet) {
|
||||
const { prefix, octets } = new IpNet(range)
|
||||
const used = Object.keys(clients).map(ip =>
|
||||
new utils.IpAddress(ip).octets.at(3),
|
||||
)
|
||||
export const ipInSubnetValidator = (subnet: string | null = null) => {
|
||||
const ipnet = subnet && utils.IpNet.parse(subnet)
|
||||
return ({ value }: AbstractControl<string>) => {
|
||||
let ip: utils.IpAddress
|
||||
try {
|
||||
ip = utils.IpAddress.parse(value)
|
||||
} catch (e) {
|
||||
return { invalidIp: 'Not a valid IP Address' }
|
||||
}
|
||||
if (!ipnet) return null
|
||||
return ipnet.contains(ip)
|
||||
? null
|
||||
: { notInSubnet: `Address is not part of ${subnet}` }
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 2; i < totalHosts(prefix); i++) {
|
||||
if (!used.includes(i)) {
|
||||
return [...octets.slice(0, 3), i].join('.')
|
||||
export function getIp({ clients, range }: MappedSubnet) {
|
||||
const net = IpNet.parse(range)
|
||||
const last = net.last()
|
||||
|
||||
for (let ip = net.add(1); ip.cmp(last) === -1; ip.add(1)) {
|
||||
if (!clients[ip.address]) {
|
||||
return ip.address
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
function totalHosts(prefix: number) {
|
||||
// Handle special cases per RFC 3021
|
||||
if (prefix === 31) return 4 // point-to-point, 2 usable addresses
|
||||
if (prefix === 32) return 3 // single host, 1 usable address
|
||||
|
||||
return Math.pow(2, 32 - prefix)
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export default class PortForwards {
|
||||
map(g =>
|
||||
Object.values(g)
|
||||
.flatMap(
|
||||
val => val.ipInfo?.subnets.map(s => new utils.IpNet(s)) || [],
|
||||
val => val.ipInfo?.subnets.map(s => utils.IpNet.parse(s)) || [],
|
||||
)
|
||||
.filter(s => s.isIpv4() && s.isPublic())
|
||||
.map(s => s.address),
|
||||
|
||||
@@ -131,12 +131,13 @@ export default class Subnets {
|
||||
}
|
||||
|
||||
private getNext(): string {
|
||||
const used = this.subnets().map(s => new utils.IpNet(s.range).octets.at(2))
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if (!used.includes(i)) {
|
||||
return `10.59.${i}.0/24`
|
||||
}
|
||||
const last =
|
||||
this.subnets()
|
||||
.map(s => utils.IpNet.parse(s.range))
|
||||
.sort((a, b) => -1 * a.cmp(b))[0] ?? utils.IpNet.parse('10.58.255.0/24')
|
||||
const next = utils.IpNet.fromIpPrefix(last.last().add(2), 24)
|
||||
if (!next.isPublic()) {
|
||||
return next.ipnet
|
||||
}
|
||||
|
||||
// No recommendation if /24 subnets are used
|
||||
|
||||
Reference in New Issue
Block a user