From f0d758f577e126c9f7abc7f74540bdd3d8d29cb9 Mon Sep 17 00:00:00 2001 From: thediveo Date: Wed, 24 Jul 2024 21:11:19 +0200 Subject: [PATCH 1/5] refact: use HW NIC icon; tweak usage of "virtual" and "virtualized" Signed-off-by: thediveo --- webui/src/components/nifinfomodal/NifInfoModal.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/webui/src/components/nifinfomodal/NifInfoModal.tsx b/webui/src/components/nifinfomodal/NifInfoModal.tsx index 6c2d76c..8140198 100644 --- a/webui/src/components/nifinfomodal/NifInfoModal.tsx +++ b/webui/src/components/nifinfomodal/NifInfoModal.tsx @@ -7,10 +7,11 @@ import { styled } from '@mui/material' import { NetworkInterface } from 'models/gw' import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Snackbar, Tooltip } from '@mui/material' import ClearIcon from '@mui/icons-material/Clear' -import LanIcon from '@mui/icons-material/Lan' import { ContentCopy } from '@mui/icons-material' import CloseIcon from '@mui/icons-material/Close' +import HwNicIcon from 'icons/nifs/HardwareNic' + const NifDialogTitle = styled(DialogTitle)(({theme}) => ({ '& .close': { position: 'relative', @@ -116,7 +117,7 @@ export const NifInfoModalProvider = ({ children }: NifInfoModalProviderProps) => onClose={handleClose} > -  Network Interface Information +  Network Interface Information
{prop('interface name', nif.name)} - {prop('type/kind', nif.kind || '(virtual) hardware')} + {prop('type/kind', nif.kind ? `virtual ${nif.kind}` : '(virtualized) hardware')} {prop('driver', nif.driverinfo.driver)} {prop('firmware version', nif.driverinfo.fwversion !== 'N/A' && nif.driverinfo.fwversion)} {prop('ext ROM version', nif.driverinfo.eromversion)} From f0785efab8bfe493764cfb6b35a1c3b8021539a3 Mon Sep 17 00:00:00 2001 From: thediveo Date: Thu, 25 Jul 2024 10:46:25 +0200 Subject: [PATCH 2/5] chore: Go deps Signed-off-by: thediveo --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d0fc82c..368f29c 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.12 require ( github.com/cenkalti/backoff/v4 v4.3.0 github.com/containernetworking/cni v1.2.3 - github.com/docker/docker v27.1.0+incompatible + github.com/docker/docker v27.1.1+incompatible github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0 github.com/getkin/kin-openapi v0.126.0 github.com/google/nftables v0.2.1-0.20240422065334-aa8348f7904c @@ -29,7 +29,7 @@ require ( github.com/thediveo/go-plugger/v3 v3.1.0 github.com/thediveo/ioctl v0.9.3 github.com/thediveo/lxkns v0.36.0 - github.com/thediveo/morbyd v0.13.0 + github.com/thediveo/morbyd v0.13.1 github.com/thediveo/namspill v0.1.6 github.com/thediveo/netdb v1.1.2 github.com/thediveo/notwork v1.6.2 diff --git a/go.sum b/go.sum index cd8ea75..f3edfb9 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v25.0.4+incompatible h1:DatRkJ+nrFoYL2HZUzjM5Z5sAmcA5XGp+AW0oEw2+cA= github.com/docker/cli v25.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v27.1.0+incompatible h1:rEHVQc4GZ0MIQKifQPHSFGV/dVgaZafgRf8fCPtDYBs= -github.com/docker/docker v27.1.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= @@ -302,8 +302,8 @@ github.com/thediveo/ioctl v0.9.3 h1:DCxyUUY15z/Zezz+wf2nlbVf3yFh0nvfM7i7KnfgG8s= github.com/thediveo/ioctl v0.9.3/go.mod h1:Ro3WW0UuPDh1QByEwNb/alva3ODM+GbRlb80u/LZU9o= github.com/thediveo/lxkns v0.36.0 h1:2UrV8WKs2C9uKscHxAyw0M5u3y9eop8wsZrBAlqitbw= github.com/thediveo/lxkns v0.36.0/go.mod h1:zYPNiNi6AK+ufDJYhivwn+OGj1hRHKF/uAEwuFpo+20= -github.com/thediveo/morbyd v0.13.0 h1:85K8vKU/Af/KnakjhOSGvdVJojxTSlFMfwO6vvlZ5t8= -github.com/thediveo/morbyd v0.13.0/go.mod h1:4g3wHYItuUdqIoIZmnOtifaI3X2PBqnCJpewBpLmlyY= +github.com/thediveo/morbyd v0.13.1 h1:mDQ27NzPXD5WIZ5t79QQazcj0tFat6HmQhbMveJ6s/A= +github.com/thediveo/morbyd v0.13.1/go.mod h1:4g3wHYItuUdqIoIZmnOtifaI3X2PBqnCJpewBpLmlyY= github.com/thediveo/namspill v0.1.6 h1:eD8puqhwIkBS78vrzJtY46eurHX0o6JIAqzgkRmMLl0= github.com/thediveo/namspill v0.1.6/go.mod h1:oRhr6rRg9z5pHuHckecgP4l9qN4YECZ22TtGs9Ma51E= github.com/thediveo/netdb v1.1.2 h1:XdLx/YJPutxrSkPYtmCAIY5sgAvxtkS1Tz+Z0UX2I+U= From a35eeb0d46dbee82100e32f657123200def27849 Mon Sep 17 00:00:00 2001 From: thediveo Date: Thu, 25 Jul 2024 10:46:25 +0200 Subject: [PATCH 3/5] fix: overeager port fw expression parser Signed-off-by: thediveo --- network/portfwd/docker/docker.go | 11 +++++++++-- network/portfwd/docker/docker_test.go | 17 ++++++----------- network/portfwd/nftget/l4proto.go | 18 +++++++++++------- network/portfwd/nftget/l4proto_test.go | 2 +- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/network/portfwd/docker/docker.go b/network/portfwd/docker/docker.go index 7718714..d1ce181 100644 --- a/network/portfwd/docker/docker.go +++ b/network/portfwd/docker/docker.go @@ -36,6 +36,13 @@ func PortForwardings(tables nufftables.TableMap, family nufftables.TableFamily) if nattable == nil { return nil } + return grabPortForwardings(nattable) +} + +// grabPortForwardings is a convenience helper to wire up the individual port +// forwarding detectors in a single place, making maintenance easier for both +// PROD and TEST. +func grabPortForwardings(nattable *nufftables.Table) []*portfinder.ForwardedPortRange { forwardedPorts := forwardedPortsMk1(nattable) forwardedPorts = append(forwardedPorts, forwardedPortsMk2(nattable)...) forwardedPorts = append(forwardedPorts, forwardedPortsMk3(nattable)...) @@ -69,7 +76,7 @@ func forwardedPortsInChainMk2(chain *nufftables.Chain) []*portfinder.ForwardedPo family := chain.Table.Family forwardedPorts := []*portfinder.ForwardedPortRange{} for _, rule := range chain.Rules { - exprs, proto := nftget.L4ProtoTcpUdp(rule.Exprs) + exprs, proto := nftget.MetaL4ProtoTcpUdp(rule.Exprs) exprs, origIP := nftget.OptionalIPv46(exprs, family) exprs, port := nufftables.OfTypeTransformed(exprs, nftget.Port) exprs, dnat := dsl.TargetDNAT(exprs) @@ -112,7 +119,7 @@ func forwardedPortsInChainMk3(chain *nufftables.Chain) []*portfinder.ForwardedPo forwardedPorts := []*portfinder.ForwardedPortRange{} for _, rule := range chain.Rules { exprs, origIP := nftget.OptionalDestIPv46(rule.Exprs, family) - exprs, proto := nftget.L4ProtoTcpUdp(exprs) + exprs, proto := nftget.PayloadL4ProtoTcpUdp(exprs) exprs, port := nftget.PayloadPort(exprs) exprs, dnat := dsl.TargetDNAT(exprs) if exprs == nil || dnat.Flags&dnatWithIPsAndPorts != dnatWithIPsAndPorts || port == 0 { diff --git a/network/portfwd/docker/docker_test.go b/network/portfwd/docker/docker_test.go index cd6cb90..bef401c 100644 --- a/network/portfwd/docker/docker_test.go +++ b/network/portfwd/docker/docker_test.go @@ -18,20 +18,12 @@ import ( "github.com/thediveo/morbyd/session" "github.com/thediveo/notwork/netns" "github.com/thediveo/nufftables" - "github.com/thediveo/nufftables/portfinder" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/thediveo/success" ) -func fwports(nattable *nufftables.Table) []*portfinder.ForwardedPortRange { - forwardedPorts := forwardedPortsMk1(nattable) - forwardedPorts = append(forwardedPorts, forwardedPortsMk2(nattable)...) - forwardedPorts = append(forwardedPorts, forwardedPortsMk3(nattable)...) - return forwardedPorts -} - var _ = Describe("Docker port forwarding", Ordered, func() { var cntrPID int @@ -76,7 +68,7 @@ var _ = Describe("Docker port forwarding", Ordered, func() { nattable := tables.Table("nat", nufftables.TableFamilyIPv4) Expect(nattable).NotTo(BeNil()) Expect(nattable.ChainsByName).NotTo(BeEmpty()) - forwardedPorts := fwports(nattable) + forwardedPorts := grabPortForwardings(nattable) Expect(forwardedPorts).To(ContainElement(And( HaveField("Protocol", "tcp"), HaveField("IP", net.ParseIP("127.0.0.1").To4()), @@ -103,8 +95,11 @@ var _ = Describe("Docker port forwarding", Ordered, func() { nattable := tables.Table("nat", nufftables.TableFamilyIPv4) Expect(nattable).NotTo(BeNil()) Expect(nattable.ChainsByName).NotTo(BeEmpty()) - forwardedPorts := fwports(nattable) - Expect(forwardedPorts).To(ContainElements( + forwardedPorts := grabPortForwardings(nattable) + // Ensure to exactly match in order to catch any false positives; this + // is possible in this case because we're looking at the nft inside the + // container and thus know what should be there and what shouldn't. + Expect(forwardedPorts).To(ConsistOf( And( HaveField("Protocol", "tcp"), HaveField("IP", net.ParseIP("127.0.0.11").To4()), diff --git a/network/portfwd/nftget/l4proto.go b/network/portfwd/nftget/l4proto.go index 6e0fc83..42851c6 100644 --- a/network/portfwd/nftget/l4proto.go +++ b/network/portfwd/nftget/l4proto.go @@ -10,13 +10,17 @@ import ( "golang.org/x/sys/unix" ) -// L4ProtoTcpUdp returns the transport layer protocol name checked for from -// either a Meta/Cmp twin-expression or a Payload/Cmp twin-expression, together -// with the remaining expressions; otherwise, it returns nil. -func L4ProtoTcpUdp(exprs nufftables.Expressions) (nufftables.Expressions, string) { - if exprs, proto := nufftables.PrefixedOfTypeTransformed(exprs, isMetaL4Proto, TcpUdp); exprs != nil { - return exprs, proto - } +// MetaL4ProtoTcpUdp returns the transport layer protocol name checked for from +// a Meta/Cmp twin-expression, together with the remaining expressions; +// otherwise, it returns nil. +func MetaL4ProtoTcpUdp(exprs nufftables.Expressions) (nufftables.Expressions, string) { + return nufftables.PrefixedOfTypeTransformed(exprs, isMetaL4Proto, TcpUdp) +} + +// PayloadL4ProtoTcpUdp returns the transport layer protocol name checked for +// from a Payload/Cmp twin-expression, together with the remaining expressions; +// otherwise, it returns nil. +func PayloadL4ProtoTcpUdp(exprs nufftables.Expressions) (nufftables.Expressions, string) { return nufftables.PrefixedOfTypeTransformed(exprs, isPayloadIPv4L4Proto, TcpUdp) } diff --git a/network/portfwd/nftget/l4proto_test.go b/network/portfwd/nftget/l4proto_test.go index 868edc1..f9795cf 100644 --- a/network/portfwd/nftget/l4proto_test.go +++ b/network/portfwd/nftget/l4proto_test.go @@ -56,7 +56,7 @@ var _ = Describe("nftables L4 proto getter", func() { if cmp != nil { exprs = append(exprs, cmp) } - exprs, protoname := L4ProtoTcpUdp(exprs) + exprs, protoname := MetaL4ProtoTcpUdp(exprs) if expectedName == "" { Expect(exprs).To(BeNil()) } else { From a8b8aea73a52ccf57e4768c949693c47a90564dd Mon Sep 17 00:00:00 2001 From: thediveo Date: Thu, 25 Jul 2024 10:46:25 +0200 Subject: [PATCH 4/5] chore: coverage badge Signed-off-by: thediveo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4273998..63e538f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ![goroutines](https://img.shields.io/badge/go%20routines-not%20leaking-success) ![file descriptors](https://img.shields.io/badge/file%20descriptors-not%20leaking-success) [![Go Report Card](https://goreportcard.com/badge/github.com/siemens/ghostwire/v2)](https://goreportcard.com/report/github.com/siemens/ghostwire/v2) -![Coverage](https://img.shields.io/badge/Coverage-77.0%25-yellow) +![Coverage](https://img.shields.io/badge/Coverage-76.9%25-yellow) **G(h)ostwire** discovers the virtual (or not) network configuration inside _Linux_ hosts – and can be deployed as a REST service or consumed as a Go From f2e502b71056c586d88994cd9f2d3032fd0cbb65 Mon Sep 17 00:00:00 2001 From: thediveo Date: Thu, 25 Jul 2024 12:27:19 +0200 Subject: [PATCH 5/5] refact: nif icons components; tweak nif information modal Signed-off-by: thediveo --- webui/src/components/nifbadge/NifBadge.tsx | 36 +----------- webui/src/components/nifhwicon/NifHWIcon.tsx | 30 ++++++++++ webui/src/components/nifhwicon/index.ts | 1 + webui/src/components/nificon/NifIcon.tsx | 55 +++++++++++++++++++ webui/src/components/nificon/index.ts | 1 + .../components/nifinfomodal/NifInfoModal.tsx | 17 ++++-- 6 files changed, 103 insertions(+), 37 deletions(-) create mode 100644 webui/src/components/nifhwicon/NifHWIcon.tsx create mode 100644 webui/src/components/nifhwicon/index.ts create mode 100644 webui/src/components/nificon/NifIcon.tsx create mode 100644 webui/src/components/nificon/index.ts diff --git a/webui/src/components/nifbadge/NifBadge.tsx b/webui/src/components/nifbadge/NifBadge.tsx index 320a4ab..4851c02 100644 --- a/webui/src/components/nifbadge/NifBadge.tsx +++ b/webui/src/components/nifbadge/NifBadge.tsx @@ -9,7 +9,6 @@ import { Button, styled, SvgIconProps } from '@mui/material' import HearingIcon from '@mui/icons-material/Hearing' import { DormantIcon, DownIcon, LowerLayerDownIcon, UpIcon } from 'icons/operstates' -import { BridgeIcon, BridgeInternalIcon, DummyIcon, HardwareNicIcon, HardwareNicPFIcon, HardwareNicVFIcon, MacvlanIcon, MacvlanMasterIcon, NicIcon, OverlayIcon, TapIcon, TunIcon, VethIcon } from 'icons/nifs' import { AddressFamily, AddressFamilySet, GHOSTWIRE_LABEL_ROOT, NetworkInterface, nifId, orderAddresses, SRIOVRole } from 'models/gw' import { OperationalState } from 'models/gw' @@ -19,6 +18,7 @@ import { relationClassName } from 'utils/relclassname' import { rgba } from 'utils/rgba' import { TargetCapture } from 'components/targetcapture' import { NifCheckbox } from 'components/nifcheckbox' +import { NifIcon } from 'components/nificon' // The outer span holding together an optional "hardware" NIC icon as well @@ -174,33 +174,6 @@ const OperstateIndicator = styled('span')(({ theme }) => ({ [`&.${OperationalState.Dormant.toLowerCase()}`]: { color: theme.palette.operstate.dormant }, })) -const nifSRIOVIcons = { - [SRIOVRole.None]: HardwareNicIcon, - [SRIOVRole.PF]: HardwareNicPFIcon, - [SRIOVRole.VF]: HardwareNicVFIcon, -} - -// Known network interface type icons, indexed by the kind property of network -// interface objects (and directly taken from what Linux' RTNETLINK tells us). -const nifTypeIcons: { [key: string]: (props: SvgIconProps) => JSX.Element } = { - 'bridge': BridgeIcon, - 'dummy': DummyIcon, - 'macvlan': MacvlanIcon, - 'tap': TapIcon, - 'tun': TunIcon, - 'veth': VethIcon, - 'vxlan': OverlayIcon, -} - -const nifIcon = (nif: NetworkInterface) => { - if (GHOSTWIRE_LABEL_ROOT + 'bridge/internal' in nif.labels) { - return BridgeInternalIcon - } - return (nif.tuntapDetails && nifTypeIcons[nif.tuntapDetails.mode]) || - (nif.macvlans && MacvlanMasterIcon) || - nifTypeIcons[nif.kind] || NicIcon -} - const operStateIcons: { [key: string]: (props: SvgIconProps) => JSX.Element } = { [OperationalState.Unknown]: UpIcon, [OperationalState.Dormant]: DormantIcon, @@ -343,11 +316,10 @@ export const NifBadge = ({ const alias = (nif.alias && nif.alias !== "") && <> (~{nif.alias}) const vid = (nif.vlanDetails) && <> VID {nif.vlanDetails.vid} - const NifIcon = nifIcon(nif) const OperstateIcon = operStateIcons[nif.operstate] const content = <> - + )} {nif.isPhysical && - + } {nif.isPromiscuous && diff --git a/webui/src/components/nifhwicon/NifHWIcon.tsx b/webui/src/components/nifhwicon/NifHWIcon.tsx new file mode 100644 index 0000000..9a51961 --- /dev/null +++ b/webui/src/components/nifhwicon/NifHWIcon.tsx @@ -0,0 +1,30 @@ +// (c) Siemens AG 2024 +// +// SPDX-License-Identifier: MIT + +import React from 'react' + +import { SvgIconProps } from '@mui/material' + +import HardwareNicIcon from 'icons/nifs/HardwareNic' +import HardwareNicPFIcon from 'icons/nifs/HardwareNicPF' +import HardwareNicVFIcon from 'icons/nifs/HardwareNicVF' +import { NetworkInterface, SRIOVRole } from 'models/gw/nif' + +const nifSRIOVIcons = { + [SRIOVRole.None]: HardwareNicIcon, + [SRIOVRole.PF]: HardwareNicPFIcon, + [SRIOVRole.VF]: HardwareNicVFIcon, +} + +export interface NifHWIconProps extends SvgIconProps { + /** network interface object describing a network interface in detail. */ + nif: NetworkInterface +} + +export const NifHWIcon = ({ nif, ...props }: NifHWIconProps) => { + const HWIcon = nifSRIOVIcons[nif.sriovrole || SRIOVRole.None] + return +} + +export default NifHWIcon diff --git a/webui/src/components/nifhwicon/index.ts b/webui/src/components/nifhwicon/index.ts new file mode 100644 index 0000000..337b627 --- /dev/null +++ b/webui/src/components/nifhwicon/index.ts @@ -0,0 +1 @@ +export { NifHWIcon } from './NifHWIcon' diff --git a/webui/src/components/nificon/NifIcon.tsx b/webui/src/components/nificon/NifIcon.tsx new file mode 100644 index 0000000..62eed08 --- /dev/null +++ b/webui/src/components/nificon/NifIcon.tsx @@ -0,0 +1,55 @@ +// (c) Siemens AG 2024 +// +// SPDX-License-Identifier: MIT + +import React from 'react' + +import { SvgIconProps } from '@mui/material' + +import { NetworkInterface } from 'models/gw/nif' +import BridgeIcon from 'icons/nifs/Bridge' +import DummyIcon from 'icons/nifs/Dummy' +import MacvlanIcon from 'icons/nifs/Macvlan' +import TapIcon from 'icons/nifs/Tap' +import TunIcon from 'icons/nifs/Tun' +import VethIcon from 'icons/nifs/Veth' +import { BridgeInternalIcon, MacvlanMasterIcon, NicIcon, OverlayIcon } from 'icons/nifs' +import { GHOSTWIRE_LABEL_ROOT } from 'models/gw/model' +import { NifHWIcon } from 'components/nifhwicon' + +// Known network interface type icons, indexed by the kind property of network +// interface objects (and directly taken from what Linux' RTNETLINK tells us). +const nifTypeIcons: { [key: string]: (props: SvgIconProps) => JSX.Element } = { + 'bridge': BridgeIcon, + 'dummy': DummyIcon, + 'macvlan': MacvlanIcon, + 'tap': TapIcon, + 'tun': TunIcon, + 'veth': VethIcon, + 'vxlan': OverlayIcon, +} + +export interface NifIconProps extends SvgIconProps { + /** network interface object describing a network interface in detail. */ + nif: NetworkInterface + /** show HW NIC icon instead of generic icon if nic is "physical". */ + considerPhysical?: boolean +} + +export const NifIcon = ({ nif, considerPhysical, ...props }: NifIconProps) => { + if (!nif) { + return <> + } + if (considerPhysical && nif.isPhysical) { + return + } + if (nif.labels && GHOSTWIRE_LABEL_ROOT + 'bridge/internal' in nif.labels) { + return + } + const Icon = (nif.tuntapDetails && nifTypeIcons[nif.tuntapDetails.mode]) || + (nif.macvlans && MacvlanMasterIcon) || + nifTypeIcons[nif.kind] || NicIcon + return +} + +export default NifIcon diff --git a/webui/src/components/nificon/index.ts b/webui/src/components/nificon/index.ts new file mode 100644 index 0000000..fecf57c --- /dev/null +++ b/webui/src/components/nificon/index.ts @@ -0,0 +1 @@ +export { NifIcon } from './NifIcon' diff --git a/webui/src/components/nifinfomodal/NifInfoModal.tsx b/webui/src/components/nifinfomodal/NifInfoModal.tsx index 8140198..0650f55 100644 --- a/webui/src/components/nifinfomodal/NifInfoModal.tsx +++ b/webui/src/components/nifinfomodal/NifInfoModal.tsx @@ -10,13 +10,17 @@ import ClearIcon from '@mui/icons-material/Clear' import { ContentCopy } from '@mui/icons-material' import CloseIcon from '@mui/icons-material/Close' -import HwNicIcon from 'icons/nifs/HardwareNic' +import { NifIcon } from 'components/nificon' -const NifDialogTitle = styled(DialogTitle)(({theme}) => ({ +const NifDialogTitle = styled(DialogTitle)(({ theme }) => ({ '& .close': { position: 'relative', right: theme.spacing(-1), - top: theme.spacing(-0.25), + top: theme.spacing(-0.5), + }, + '& .nificon.MuiSvgIcon-root': { + position: 'relative', + top: theme.spacing(0.5), }, })) @@ -117,7 +121,12 @@ export const NifInfoModalProvider = ({ children }: NifInfoModalProviderProps) => onClose={handleClose} > -  Network Interface Information +  Network Interface Information