Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for IPv6 network/peer configuration #314

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 80 additions & 29 deletions src/app/(dashboard)/peer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import { useHasExitNodes } from "@/modules/exit-node/useHasExitNodes";
import useGroupHelper from "@/modules/groups/useGroupHelper";
import AddRouteDropdownButton from "@/modules/peer/AddRouteDropdownButton";
import PeerRoutesTable from "@/modules/peer/PeerRoutesTable";
import {SelectDropdown} from "@components/select/SelectDropdown";

export default function PeerPage() {
const queryParameter = useSearchParams();
Expand All @@ -86,6 +87,9 @@ function PeerOverview() {
const [loginExpiration, setLoginExpiration] = useState(
peer.login_expiration_enabled,
);
const [ipv6Enabled, setIpv6Enabled] = useState(
peer.ipv6_enabled,
);
const [selectedGroups, setSelectedGroups, { getAllGroupCalls }] =
useGroupHelper({
initial: peerGroups,
Expand All @@ -108,10 +112,11 @@ function PeerOverview() {
ssh,
selectedGroups,
loginExpiration,
ipv6Enabled
]);

const updatePeer = async () => {
const updateRequest = update(name, ssh, loginExpiration);
const updateRequest = update(name, ssh, loginExpiration, ipv6Enabled);
const groupCalls = getAllGroupCalls();
const batchCall = groupCalls
? [...groupCalls, updateRequest]
Expand All @@ -122,7 +127,7 @@ function PeerOverview() {
promise: Promise.all(batchCall).then(() => {
mutate("/peers/" + peer.id);
mutate("/groups");
updateHasChangedRef([name, ssh, selectedGroups, loginExpiration]);
updateHasChangedRef([name, ssh, selectedGroups, loginExpiration, ipv6Enabled]);
}),
loadingMessage: "Saving the peer...",
});
Expand All @@ -137,23 +142,23 @@ function PeerOverview() {
<div className={"p-default py-6 mb-4"}>
<Breadcrumbs>
<Breadcrumbs.Item
href={"/peers"}
label={"Peers"}
icon={<PeerIcon size={13} />}
href={"/peers"}
label={"Peers"}
icon={<PeerIcon size={13}/>}
/>
<Breadcrumbs.Item label={peer.ip} active />
<Breadcrumbs.Item label={peer.ip} active/>
</Breadcrumbs>

<div className={"flex justify-between max-w-6xl items-start"}>
<div>
<div className={"flex items-center gap-3"}>
<h1 className={"flex items-center gap-3"}>
<CircleIcon
active={peer.connected}
size={12}
className={"mb-[3px] shrink-0"}
active={peer.connected}
size={12}
className={"mb-[3px] shrink-0"}
/>
<TextWithTooltip text={name} maxChars={30} />
<TextWithTooltip text={name} maxChars={30}/>

{!isUser && (
<Modal
Expand Down Expand Up @@ -181,7 +186,7 @@ function PeerOverview() {
</Modal>
)}
</h1>
<LoginExpiredBadge loginExpired={peer.login_expired} />
<LoginExpiredBadge loginExpired={peer.login_expired}/>
</div>
<div className={"flex items-center gap-8"}>
<Paragraph className={"flex items-center"}>
Expand All @@ -191,9 +196,9 @@ function PeerOverview() {
</div>
<div className={"flex gap-4"}>
<Button
variant={"default"}
className={"w-full"}
onClick={() => router.push("/peers")}
variant={"default"}
className={"w-full"}
onClick={() => router.push("/peers")}
>
Cancel
</Button>
Expand All @@ -209,7 +214,7 @@ function PeerOverview() {
</div>

<div className={"flex gap-10 w-full mt-5 max-w-6xl"}>
<PeerInformationCard peer={peer} />
<PeerInformationCard peer={peer}/>

<div className={"flex flex-col gap-6 w-1/2"}>
<FullTooltip
Expand All @@ -222,7 +227,7 @@ function PeerOverview() {
{!peer.user_id ? (
<>
<>
<IconInfoCircle size={14} />
<IconInfoCircle size={14}/>
<span>
Login expiration is disabled for all peers added
with an setup-key.
Expand All @@ -231,7 +236,7 @@ function PeerOverview() {
</>
) : (
<>
<LockIcon size={14} />
<LockIcon size={14}/>
<span>
{`You don't have the required permissions to update this
setting.`}
Expand All @@ -249,7 +254,7 @@ function PeerOverview() {
onChange={setLoginExpiration}
label={
<>
<IconCloudLock size={16} />
<IconCloudLock size={16}/>
Login Expiration
</>
}
Expand All @@ -265,7 +270,7 @@ function PeerOverview() {
"flex gap-2 items-center !text-nb-gray-300 text-xs"
}
>
<LockIcon size={14} />
<LockIcon size={14}/>
<span>
{`You don't have the required permissions to update this
setting.`}
Expand All @@ -286,7 +291,7 @@ function PeerOverview() {
}
label={
<>
<TerminalSquare size={16} />
<TerminalSquare size={16}/>
SSH Access
</>
}
Expand All @@ -308,7 +313,7 @@ function PeerOverview() {
"flex gap-2 items-center !text-nb-gray-300 text-xs"
}
>
<LockIcon size={14} />
<LockIcon size={14}/>
<span>
{`You don't have the required permissions to update this
setting.`}
Expand All @@ -327,11 +332,47 @@ function PeerOverview() {
/>
</FullTooltip>
</div>
<div>
<Label>IPv6 Support</Label>
<HelpText>
Whether to enable IPv6, disable it, or enable IPv6 automatically.
Overrides groupwide setting if set to something else than Automatic. <br/>
Automatic enables IPv6 if it is enabled by at least one group or if the peer is used in at least one
IPv6 route.
</HelpText>
<FullTooltip
content={
<div
className={
"flex gap-2 items-center !text-nb-gray-300 text-xs"
}
>
<IconInfoCircle size={14}/>
<span>
IPv6 Support requires a recent version of the NetBird client as well as a supported OS (Linux with nftables).
</span>
</div>
}
className={"w-full block"}
disabled={peer.ipv6_supported}
>
<SelectDropdown
disabled={!peer.ipv6_supported}
value={ipv6Enabled}
onChange={setIpv6Enabled}
options={[
{label: "Force enabled", value: "enabled"},
{label: "Automatic", value: "auto"},
{label: "Force disabled", value: "disabled"},
]}
/>
</FullTooltip>
</div>
</div>
</div>
</div>

<Separator />
<Separator/>

{isLinux && !isUser ? (
<div className={"px-8 py-6"}>
Expand All @@ -346,12 +387,12 @@ function PeerOverview() {
</div>
<div className={"inline-flex gap-4 justify-end"}>
<div className={"gap-4 flex"}>
<AddExitNodeButton peer={peer} firstTime={!hasExitNodes} />
<AddRouteDropdownButton />
<AddExitNodeButton peer={peer} firstTime={!hasExitNodes}/>
<AddRouteDropdownButton/>
</div>
</div>
</div>
<PeerRoutesTable peer={peer} />
<PeerRoutesTable peer={peer}/>
</div>
</div>
) : null}
Expand All @@ -360,8 +401,8 @@ function PeerOverview() {
);
}

function PeerInformationCard({ peer }: { peer: Peer }) {
const { isLoading, getRegionByPeer } = useCountries();
function PeerInformationCard({peer}: { peer: Peer }) {
const {isLoading, getRegionByPeer} = useCountries();

const countryText = useMemo(() => {
return getRegionByPeer(peer);
Expand All @@ -375,13 +416,23 @@ function PeerInformationCard({ peer }: { peer: Peer }) {
copyText={"NetBird IP-Address"}
label={
<>
<MapPin size={16} />
NetBird IP-Address
<MapPin size={16}/>
NetBird IPv4-Address
</>
}
value={peer.ip}
/>

<Card.ListItem
label={
<>
<MapPin size={16}/>
NetBird IPv6-Address
</>
}
value={peer.ip6}
/>

<Card.ListItem
copy
copyText={"Public IP-Address"}
Expand Down
6 changes: 3 additions & 3 deletions src/components/PeerGroupSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,16 @@ export function PeerGroupSelector({
if (!group && !option) {
setDropdownOptions((previous) => [
...previous,
{ name: name, peers: groupPeers },
{ name: name, peers: groupPeers, ipv6_enabled: false },
]);
}

if (max == 1 && values.length == 1) {
onChange([{ name: name, id: group?.id, peers: groupPeers }]);
onChange([{ name: name, id: group?.id, peers: groupPeers, ipv6_enabled: group == null ? false : group.ipv6_enabled }]);
} else {
onChange((previous) => [
...previous,
{ name: name, id: group?.id, peers: groupPeers },
{ name: name, id: group?.id, peers: groupPeers, ipv6_enabled: group == null ? false : group.ipv6_enabled },
]);
}

Expand Down
7 changes: 5 additions & 2 deletions src/contexts/PeerProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ const PeerContext = React.createContext(
name: string,
ssh: boolean,
loginExpiration: boolean,
approval_required?: boolean,
ipv6_enabled: string,
approval_required?: boolean
) => Promise<Peer>;
openSSHDialog: () => Promise<boolean>;
deletePeer: () => void;
Expand Down Expand Up @@ -65,7 +66,8 @@ export default function PeerProvider({ children, peer }: Props) {
name: string,
ssh: boolean,
loginExpiration: boolean,
approval_required?: boolean,
ipv6_enabled: string,
approval_required?: boolean
) => {
return peerRequest.put(
{
Expand All @@ -78,6 +80,7 @@ export default function PeerProvider({ children, peer }: Props) {
: peer.login_expiration_enabled,
approval_required:
approval_required == undefined ? undefined : approval_required,
ipv6_enabled: ipv6_enabled != undefined ? ipv6_enabled : peer.ipv6_enabled
},
`/${peer.id}`,
);
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface Group {
name: string;
peers?: GroupPeer[] | string[];
peers_count?: number;
ipv6_enabled: boolean
}

export interface GroupPeer {
Expand Down
36 changes: 36 additions & 0 deletions src/interfaces/Nameserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ export const NameserverPresets: Record<string, NameserverGroup> = {
port: 53,
id: "2",
},
{
ip: "2001:4860:4860::8888",
ns_type: "udp",
port: 53,
id: "3",
},
{
ip: "2001:4860:4860::8844",
ns_type: "udp",
port: 53,
id: "4",
},
],
groups: [],
enabled: true,
Expand All @@ -81,6 +93,18 @@ export const NameserverPresets: Record<string, NameserverGroup> = {
port: 53,
id: "2",
},
{
ip: "2606:4700:4700::1111",
ns_type: "udp",
port: 53,
id: "3",
},
{
ip: "2606:4700:4700::1001",
ns_type: "udp",
port: 53,
id: "4",
},
],
groups: [],
enabled: true,
Expand All @@ -104,6 +128,18 @@ export const NameserverPresets: Record<string, NameserverGroup> = {
port: 53,
id: "2",
},
{
ip: "2620:fe::fe",
ns_type: "udp",
port: 53,
id: "3",
},
{
ip: "2620:fe::9",
ns_type: "udp",
port: 53,
id: "4",
},
],
groups: [],
enabled: true,
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/Peer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface Peer {
id?: string;
name: string;
ip: string;
ip6?: string,
connected: boolean;
last_seen: Date;
os: string;
Expand All @@ -19,6 +20,8 @@ export interface Peer {
last_login: Date;
login_expired: boolean;
login_expiration_enabled: boolean;
ipv6_supported: boolean,
ipv6_enabled: string,
approval_required: boolean;
city_name: string;
country_code: string;
Expand Down
Loading