Skip to content

Commit 4e966f7

Browse files
authored
Merge pull request #59 from siemens/develop
Develop
2 parents 7c2ae8e + f2e502b commit 4e966f7

File tree

13 files changed

+139
-66
lines changed

13 files changed

+139
-66
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
![goroutines](https://img.shields.io/badge/go%20routines-not%20leaking-success)
1313
![file descriptors](https://img.shields.io/badge/file%20descriptors-not%20leaking-success)
1414
[![Go Report Card](https://goreportcard.com/badge/github.com/siemens/ghostwire/v2)](https://goreportcard.com/report/github.com/siemens/ghostwire/v2)
15-
![Coverage](https://img.shields.io/badge/Coverage-77.0%25-yellow)
15+
![Coverage](https://img.shields.io/badge/Coverage-76.9%25-yellow)
1616

1717
**G(h)ostwire** discovers the virtual (or not) network configuration inside
1818
_Linux_ hosts – and can be deployed as a REST service or consumed as a Go

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ replace github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.12
77
require (
88
github.com/cenkalti/backoff/v4 v4.3.0
99
github.com/containernetworking/cni v1.2.3
10-
github.com/docker/docker v27.1.0+incompatible
10+
github.com/docker/docker v27.1.1+incompatible
1111
github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0
1212
github.com/getkin/kin-openapi v0.126.0
1313
github.com/google/nftables v0.2.1-0.20240422065334-aa8348f7904c
@@ -29,7 +29,7 @@ require (
2929
github.com/thediveo/go-plugger/v3 v3.1.0
3030
github.com/thediveo/ioctl v0.9.3
3131
github.com/thediveo/lxkns v0.36.0
32-
github.com/thediveo/morbyd v0.13.0
32+
github.com/thediveo/morbyd v0.13.1
3333
github.com/thediveo/namspill v0.1.6
3434
github.com/thediveo/netdb v1.1.2
3535
github.com/thediveo/notwork v1.6.2

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
6363
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
6464
github.com/docker/cli v25.0.4+incompatible h1:DatRkJ+nrFoYL2HZUzjM5Z5sAmcA5XGp+AW0oEw2+cA=
6565
github.com/docker/cli v25.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
66-
github.com/docker/docker v27.1.0+incompatible h1:rEHVQc4GZ0MIQKifQPHSFGV/dVgaZafgRf8fCPtDYBs=
67-
github.com/docker/docker v27.1.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
66+
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
67+
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
6868
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
6969
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
7070
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=
302302
github.com/thediveo/ioctl v0.9.3/go.mod h1:Ro3WW0UuPDh1QByEwNb/alva3ODM+GbRlb80u/LZU9o=
303303
github.com/thediveo/lxkns v0.36.0 h1:2UrV8WKs2C9uKscHxAyw0M5u3y9eop8wsZrBAlqitbw=
304304
github.com/thediveo/lxkns v0.36.0/go.mod h1:zYPNiNi6AK+ufDJYhivwn+OGj1hRHKF/uAEwuFpo+20=
305-
github.com/thediveo/morbyd v0.13.0 h1:85K8vKU/Af/KnakjhOSGvdVJojxTSlFMfwO6vvlZ5t8=
306-
github.com/thediveo/morbyd v0.13.0/go.mod h1:4g3wHYItuUdqIoIZmnOtifaI3X2PBqnCJpewBpLmlyY=
305+
github.com/thediveo/morbyd v0.13.1 h1:mDQ27NzPXD5WIZ5t79QQazcj0tFat6HmQhbMveJ6s/A=
306+
github.com/thediveo/morbyd v0.13.1/go.mod h1:4g3wHYItuUdqIoIZmnOtifaI3X2PBqnCJpewBpLmlyY=
307307
github.com/thediveo/namspill v0.1.6 h1:eD8puqhwIkBS78vrzJtY46eurHX0o6JIAqzgkRmMLl0=
308308
github.com/thediveo/namspill v0.1.6/go.mod h1:oRhr6rRg9z5pHuHckecgP4l9qN4YECZ22TtGs9Ma51E=
309309
github.com/thediveo/netdb v1.1.2 h1:XdLx/YJPutxrSkPYtmCAIY5sgAvxtkS1Tz+Z0UX2I+U=

network/portfwd/docker/docker.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ func PortForwardings(tables nufftables.TableMap, family nufftables.TableFamily)
3636
if nattable == nil {
3737
return nil
3838
}
39+
return grabPortForwardings(nattable)
40+
}
41+
42+
// grabPortForwardings is a convenience helper to wire up the individual port
43+
// forwarding detectors in a single place, making maintenance easier for both
44+
// PROD and TEST.
45+
func grabPortForwardings(nattable *nufftables.Table) []*portfinder.ForwardedPortRange {
3946
forwardedPorts := forwardedPortsMk1(nattable)
4047
forwardedPorts = append(forwardedPorts, forwardedPortsMk2(nattable)...)
4148
forwardedPorts = append(forwardedPorts, forwardedPortsMk3(nattable)...)
@@ -69,7 +76,7 @@ func forwardedPortsInChainMk2(chain *nufftables.Chain) []*portfinder.ForwardedPo
6976
family := chain.Table.Family
7077
forwardedPorts := []*portfinder.ForwardedPortRange{}
7178
for _, rule := range chain.Rules {
72-
exprs, proto := nftget.L4ProtoTcpUdp(rule.Exprs)
79+
exprs, proto := nftget.MetaL4ProtoTcpUdp(rule.Exprs)
7380
exprs, origIP := nftget.OptionalIPv46(exprs, family)
7481
exprs, port := nufftables.OfTypeTransformed(exprs, nftget.Port)
7582
exprs, dnat := dsl.TargetDNAT(exprs)
@@ -112,7 +119,7 @@ func forwardedPortsInChainMk3(chain *nufftables.Chain) []*portfinder.ForwardedPo
112119
forwardedPorts := []*portfinder.ForwardedPortRange{}
113120
for _, rule := range chain.Rules {
114121
exprs, origIP := nftget.OptionalDestIPv46(rule.Exprs, family)
115-
exprs, proto := nftget.L4ProtoTcpUdp(exprs)
122+
exprs, proto := nftget.PayloadL4ProtoTcpUdp(exprs)
116123
exprs, port := nftget.PayloadPort(exprs)
117124
exprs, dnat := dsl.TargetDNAT(exprs)
118125
if exprs == nil || dnat.Flags&dnatWithIPsAndPorts != dnatWithIPsAndPorts || port == 0 {

network/portfwd/docker/docker_test.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,12 @@ import (
1818
"github.com/thediveo/morbyd/session"
1919
"github.com/thediveo/notwork/netns"
2020
"github.com/thediveo/nufftables"
21-
"github.com/thediveo/nufftables/portfinder"
2221

2322
. "github.com/onsi/ginkgo/v2"
2423
. "github.com/onsi/gomega"
2524
. "github.com/thediveo/success"
2625
)
2726

28-
func fwports(nattable *nufftables.Table) []*portfinder.ForwardedPortRange {
29-
forwardedPorts := forwardedPortsMk1(nattable)
30-
forwardedPorts = append(forwardedPorts, forwardedPortsMk2(nattable)...)
31-
forwardedPorts = append(forwardedPorts, forwardedPortsMk3(nattable)...)
32-
return forwardedPorts
33-
}
34-
3527
var _ = Describe("Docker port forwarding", Ordered, func() {
3628

3729
var cntrPID int
@@ -76,7 +68,7 @@ var _ = Describe("Docker port forwarding", Ordered, func() {
7668
nattable := tables.Table("nat", nufftables.TableFamilyIPv4)
7769
Expect(nattable).NotTo(BeNil())
7870
Expect(nattable.ChainsByName).NotTo(BeEmpty())
79-
forwardedPorts := fwports(nattable)
71+
forwardedPorts := grabPortForwardings(nattable)
8072
Expect(forwardedPorts).To(ContainElement(And(
8173
HaveField("Protocol", "tcp"),
8274
HaveField("IP", net.ParseIP("127.0.0.1").To4()),
@@ -103,8 +95,11 @@ var _ = Describe("Docker port forwarding", Ordered, func() {
10395
nattable := tables.Table("nat", nufftables.TableFamilyIPv4)
10496
Expect(nattable).NotTo(BeNil())
10597
Expect(nattable.ChainsByName).NotTo(BeEmpty())
106-
forwardedPorts := fwports(nattable)
107-
Expect(forwardedPorts).To(ContainElements(
98+
forwardedPorts := grabPortForwardings(nattable)
99+
// Ensure to exactly match in order to catch any false positives; this
100+
// is possible in this case because we're looking at the nft inside the
101+
// container and thus know what should be there and what shouldn't.
102+
Expect(forwardedPorts).To(ConsistOf(
108103
And(
109104
HaveField("Protocol", "tcp"),
110105
HaveField("IP", net.ParseIP("127.0.0.11").To4()),

network/portfwd/nftget/l4proto.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ import (
1010
"golang.org/x/sys/unix"
1111
)
1212

13-
// L4ProtoTcpUdp returns the transport layer protocol name checked for from
14-
// either a Meta/Cmp twin-expression or a Payload/Cmp twin-expression, together
15-
// with the remaining expressions; otherwise, it returns nil.
16-
func L4ProtoTcpUdp(exprs nufftables.Expressions) (nufftables.Expressions, string) {
17-
if exprs, proto := nufftables.PrefixedOfTypeTransformed(exprs, isMetaL4Proto, TcpUdp); exprs != nil {
18-
return exprs, proto
19-
}
13+
// MetaL4ProtoTcpUdp returns the transport layer protocol name checked for from
14+
// a Meta/Cmp twin-expression, together with the remaining expressions;
15+
// otherwise, it returns nil.
16+
func MetaL4ProtoTcpUdp(exprs nufftables.Expressions) (nufftables.Expressions, string) {
17+
return nufftables.PrefixedOfTypeTransformed(exprs, isMetaL4Proto, TcpUdp)
18+
}
19+
20+
// PayloadL4ProtoTcpUdp returns the transport layer protocol name checked for
21+
// from a Payload/Cmp twin-expression, together with the remaining expressions;
22+
// otherwise, it returns nil.
23+
func PayloadL4ProtoTcpUdp(exprs nufftables.Expressions) (nufftables.Expressions, string) {
2024
return nufftables.PrefixedOfTypeTransformed(exprs, isPayloadIPv4L4Proto, TcpUdp)
2125
}
2226

network/portfwd/nftget/l4proto_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ var _ = Describe("nftables L4 proto getter", func() {
5656
if cmp != nil {
5757
exprs = append(exprs, cmp)
5858
}
59-
exprs, protoname := L4ProtoTcpUdp(exprs)
59+
exprs, protoname := MetaL4ProtoTcpUdp(exprs)
6060
if expectedName == "" {
6161
Expect(exprs).To(BeNil())
6262
} else {

webui/src/components/nifbadge/NifBadge.tsx

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { Button, styled, SvgIconProps } from '@mui/material'
99
import HearingIcon from '@mui/icons-material/Hearing'
1010

1111
import { DormantIcon, DownIcon, LowerLayerDownIcon, UpIcon } from 'icons/operstates'
12-
import { BridgeIcon, BridgeInternalIcon, DummyIcon, HardwareNicIcon, HardwareNicPFIcon, HardwareNicVFIcon, MacvlanIcon, MacvlanMasterIcon, NicIcon, OverlayIcon, TapIcon, TunIcon, VethIcon } from 'icons/nifs'
1312

1413
import { AddressFamily, AddressFamilySet, GHOSTWIRE_LABEL_ROOT, NetworkInterface, nifId, orderAddresses, SRIOVRole } from 'models/gw'
1514
import { OperationalState } from 'models/gw'
@@ -19,6 +18,7 @@ import { relationClassName } from 'utils/relclassname'
1918
import { rgba } from 'utils/rgba'
2019
import { TargetCapture } from 'components/targetcapture'
2120
import { NifCheckbox } from 'components/nifcheckbox'
21+
import { NifIcon } from 'components/nificon'
2222

2323

2424
// The outer span holding together an optional "hardware" NIC icon as well
@@ -174,33 +174,6 @@ const OperstateIndicator = styled('span')(({ theme }) => ({
174174
[`&.${OperationalState.Dormant.toLowerCase()}`]: { color: theme.palette.operstate.dormant },
175175
}))
176176

177-
const nifSRIOVIcons = {
178-
[SRIOVRole.None]: HardwareNicIcon,
179-
[SRIOVRole.PF]: HardwareNicPFIcon,
180-
[SRIOVRole.VF]: HardwareNicVFIcon,
181-
}
182-
183-
// Known network interface type icons, indexed by the kind property of network
184-
// interface objects (and directly taken from what Linux' RTNETLINK tells us).
185-
const nifTypeIcons: { [key: string]: (props: SvgIconProps) => JSX.Element } = {
186-
'bridge': BridgeIcon,
187-
'dummy': DummyIcon,
188-
'macvlan': MacvlanIcon,
189-
'tap': TapIcon,
190-
'tun': TunIcon,
191-
'veth': VethIcon,
192-
'vxlan': OverlayIcon,
193-
}
194-
195-
const nifIcon = (nif: NetworkInterface) => {
196-
if (GHOSTWIRE_LABEL_ROOT + 'bridge/internal' in nif.labels) {
197-
return BridgeInternalIcon
198-
}
199-
return (nif.tuntapDetails && nifTypeIcons[nif.tuntapDetails.mode]) ||
200-
(nif.macvlans && MacvlanMasterIcon) ||
201-
nifTypeIcons[nif.kind] || NicIcon
202-
}
203-
204177
const operStateIcons: { [key: string]: (props: SvgIconProps) => JSX.Element } = {
205178
[OperationalState.Unknown]: UpIcon,
206179
[OperationalState.Dormant]: DormantIcon,
@@ -343,11 +316,10 @@ export const NifBadge = ({
343316
const alias = (nif.alias && nif.alias !== "") && <> (~<span className="alias">{nif.alias}</span>)</>
344317
const vid = (nif.vlanDetails) && <> VID&nbsp;{nif.vlanDetails.vid}</>
345318

346-
const NifIcon = nifIcon(nif)
347319
const OperstateIcon = operStateIcons[nif.operstate]
348320

349321
const content = <>
350-
<NifIcon />
322+
<NifIcon nif={nif} />
351323
<OperstateIndicator
352324
as={OperstateIcon}
353325
className={nif.operstate.toLowerCase()}
@@ -434,8 +406,6 @@ export const NifBadge = ({
434406
}
435407
}
436408

437-
const HWIcon = nifSRIOVIcons[nif.sriovrole || SRIOVRole.None]
438-
439409
// With lots of information prepared we can finally render the badge,
440410
// optionally wrapped into a tooltip with some detail information about
441411
// the network interface.
@@ -451,7 +421,7 @@ export const NifBadge = ({
451421
: <Capture className="nifcaptureicon alignright" target={nif} />)}
452422
{nif.isPhysical &&
453423
<HWNif className="nifbagdeicon">
454-
<HWIcon />
424+
<NifIcon nif={nif} considerPhysical />
455425
</HWNif>
456426
}
457427
{nif.isPromiscuous &&
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// (c) Siemens AG 2024
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
import React from 'react'
6+
7+
import { SvgIconProps } from '@mui/material'
8+
9+
import HardwareNicIcon from 'icons/nifs/HardwareNic'
10+
import HardwareNicPFIcon from 'icons/nifs/HardwareNicPF'
11+
import HardwareNicVFIcon from 'icons/nifs/HardwareNicVF'
12+
import { NetworkInterface, SRIOVRole } from 'models/gw/nif'
13+
14+
const nifSRIOVIcons = {
15+
[SRIOVRole.None]: HardwareNicIcon,
16+
[SRIOVRole.PF]: HardwareNicPFIcon,
17+
[SRIOVRole.VF]: HardwareNicVFIcon,
18+
}
19+
20+
export interface NifHWIconProps extends SvgIconProps {
21+
/** network interface object describing a network interface in detail. */
22+
nif: NetworkInterface
23+
}
24+
25+
export const NifHWIcon = ({ nif, ...props }: NifHWIconProps) => {
26+
const HWIcon = nifSRIOVIcons[nif.sriovrole || SRIOVRole.None]
27+
return <HWIcon {...props} />
28+
}
29+
30+
export default NifHWIcon
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { NifHWIcon } from './NifHWIcon'

0 commit comments

Comments
 (0)