diff --git a/scripts/make-fake-data.js b/scripts/make-fake-data.js
index d4af560..c492d53 100644
--- a/scripts/make-fake-data.js
+++ b/scripts/make-fake-data.js
@@ -382,7 +382,7 @@ function getDNSInfo() {
.word()
.toLowerCase()
.split(" ", 2)[0],
- cidr: faker.random.number({ min: 1, max: 32 })
+ cidr: faker.random.arrayElement([8, 16, 24, 32])
}
};
}
diff --git a/src/components/settings/ConditionalForwardingSettings.tsx b/src/components/settings/ConditionalForwardingSettings.tsx
index bf58d49..23547c3 100644
--- a/src/components/settings/ConditionalForwardingSettings.tsx
+++ b/src/components/settings/ConditionalForwardingSettings.tsx
@@ -23,6 +23,7 @@ export interface ConditionalForwardingSettingsProps {
settings: ConditionalForwardingObject;
onUpdate: (settings: ConditionalForwardingObject) => void;
isRouterIpValid: boolean;
+ isCidrValid: boolean;
isDomainValid: boolean;
t: i18next.TFunction;
}
@@ -31,6 +32,7 @@ const ConditionalForwardingSettings = ({
settings,
onUpdate,
isRouterIpValid,
+ isCidrValid,
isDomainValid,
t
}: ConditionalForwardingSettingsProps) => (
@@ -67,12 +69,17 @@ const ConditionalForwardingSettings = ({
{
- const cidr = parseInt(e.target.value);
+ let cidr = parseInt(e.target.value);
- // Only allow numbers
- if (isNaN(cidr)) {
+ if (e.target.value.length === 0) {
+ // Use -1 as an internal representation of the empty string.
+ // It will show the form as invalid and make the text field
+ // function as the user expects it to.
+ cidr = -1;
+ } else if (isNaN(cidr)) {
return;
}
diff --git a/src/components/settings/DNSInfo.tsx b/src/components/settings/DNSInfo.tsx
index 6b87b79..f7c7b62 100644
--- a/src/components/settings/DNSInfo.tsx
+++ b/src/components/settings/DNSInfo.tsx
@@ -23,7 +23,13 @@ import ConditionalForwardingSettings, {
} from "./ConditionalForwardingSettings";
import DnsOptionSettings, { DnsOptionsObject } from "./DnsOptionSettings";
import Alert, { AlertType } from "../common/Alert";
-import { isValidHostname, isValidIpv4, isValidIpv6 } from "../../util/validate";
+import {
+ isValidHostname,
+ isValidIpv4,
+ isValidIpv4Cidr,
+ isValidIpv6,
+ isValidIpv6Cidr
+} from "../../util/validate";
export interface DNSInfoState {
alertMessage: string;
@@ -195,6 +201,11 @@ class DNSInfo extends Component {
address => isValidIpv4(address) || isValidIpv6(address)
);
+ const isCidrValid = this.isCFSettingValid(
+ this.state.conditionalForwarding.cidr.toString(),
+ cidr => isValidIpv4Cidr(cidr) || isValidIpv6Cidr(cidr)
+ );
+
const isDomainValid = this.isCFSettingValid(
this.state.conditionalForwarding.domain,
isValidHostname
@@ -226,6 +237,7 @@ class DNSInfo extends Component {
settings={this.state.conditionalForwarding}
onUpdate={this.handleConditionalForwardingUpdate}
isRouterIpValid={isRouterIpValid}
+ isCidrValid={isCidrValid}
isDomainValid={isDomainValid}
t={t}
/>
@@ -239,7 +251,12 @@ class DNSInfo extends Component {
diff --git a/src/util/__tests__/validate.test.tsx b/src/util/__tests__/validate.test.tsx
index 2b91f08..1677ef9 100644
--- a/src/util/__tests__/validate.test.tsx
+++ b/src/util/__tests__/validate.test.tsx
@@ -12,8 +12,10 @@ import {
isPositiveNumber,
isValidDomain,
isValidIpv4,
+ isValidIpv4Cidr,
isValidIpv4OptionalPort,
isValidIpv6,
+ isValidIpv6Cidr,
isValidIpv6OptionalPort,
isValidRegex
} from "../validate";
@@ -230,6 +232,40 @@ describe("Testing the validation functions", () => {
});
});
+ describe("isValidIpv4Cidr", () => {
+ it("passes 8", () => {
+ expect(isValidIpv4Cidr("8")).toBe(true);
+ });
+
+ it("passes 16", () => {
+ expect(isValidIpv4Cidr("16")).toBe(true);
+ });
+
+ it("passes 24", () => {
+ expect(isValidIpv4Cidr("24")).toBe(true);
+ });
+
+ it("passes 32", () => {
+ expect(isValidIpv4Cidr("32")).toBe(true);
+ });
+
+ it("fails -1", () => {
+ expect(isValidIpv4Cidr("-1")).toBe(false);
+ });
+
+ it("fails 0", () => {
+ expect(isValidIpv4Cidr("0")).toBe(false);
+ });
+
+ it("fails 28", () => {
+ expect(isValidIpv4Cidr("28")).toBe(false);
+ });
+
+ it("fails 40", () => {
+ expect(isValidIpv4Cidr("40")).toBe(false);
+ });
+ });
+
describe("isValidIpv6", () => {
it("passes 1fff:0:a88:85a3::ac1f", () => {
expect(isValidIpv6("1fff:0:a88:85a3::ac1f")).toBe(true);
@@ -291,4 +327,38 @@ describe("Testing the validation functions", () => {
expect(isValidIpv6OptionalPort("[::1]")).toBe(false);
});
});
+
+ describe("isValidIpv6Cidr", () => {
+ it("passes 8", () => {
+ expect(isValidIpv6Cidr("8")).toBe(true);
+ });
+
+ it("passes 64", () => {
+ expect(isValidIpv6Cidr("64")).toBe(true);
+ });
+
+ it("passes 56", () => {
+ expect(isValidIpv6Cidr("56")).toBe(true);
+ });
+
+ it("passes 128", () => {
+ expect(isValidIpv6Cidr("128")).toBe(true);
+ });
+
+ it("fails -1", () => {
+ expect(isValidIpv6Cidr("-1")).toBe(false);
+ });
+
+ it("fails 0", () => {
+ expect(isValidIpv6Cidr("0")).toBe(false);
+ });
+
+ it("fails 63", () => {
+ expect(isValidIpv6Cidr("63")).toBe(false);
+ });
+
+ it("fails 150", () => {
+ expect(isValidIpv6Cidr("150")).toBe(false);
+ });
+ });
});
diff --git a/src/util/validate.tsx b/src/util/validate.tsx
index 1efa46b..712258d 100644
--- a/src/util/validate.tsx
+++ b/src/util/validate.tsx
@@ -95,6 +95,15 @@ export function isValidIpv4OptionalPort(address: string): boolean {
);
}
+/**
+ * Check if the string is a valid IPv4 CIDR number which dnsmasq accepts
+ *
+ * @param cidr The string to check
+ */
+export function isValidIpv4Cidr(cidr: string): boolean {
+ return ["8", "16", "24", "32"].includes(cidr);
+}
+
/**
* Check if the string is a valid IPv6 address. This function does not do a
* thorough check of the IPv6 address; the backend will check it in detail.
@@ -118,3 +127,14 @@ export function isValidIpv6(address: string): boolean {
export function isValidIpv6OptionalPort(address: string): boolean {
return /^(\[[a-fA-F0-9:]+]:\d+|[a-fA-F0-9:]+)$/.test(address);
}
+
+/**
+ * Check if the string is a valid IPv6 CIDR number which dnsmasq accepts
+ *
+ * @param cidr The string to check
+ */
+export function isValidIpv6Cidr(cidr: string): boolean {
+ const cidrNum = parseInt(cidr);
+
+ return !isNaN(cidrNum) && cidrNum > 0 && cidrNum <= 128 && cidrNum % 4 === 0;
+}