TAP/TUN 장치를 사용 중인 프로세스에 올바르게 일치시키고 싶습니다.외부ioctl()
이러한 프로세스는 TAP/TUN 장치를 사용합니다(즉, 프로세스 자체 내부의 특정 파일 설명자에 액세스할 수 없기 때문에 s를 실행할 수 없습니다 ).
나는 다음 질문에 대한 답을 알고 있습니다탭 인터페이스와 해당 파일 설명자 간의 연결을 찾는 방법은 무엇입니까?즉, 해당 TAP/TUN 네트워크 인터페이스의 이름을 제공하는 /proc/[PID]/fdinfo/[FD]
추가 키-값 쌍이 있습니다 .iff:
그러나 네트워크 네임스페이스에는 문제가 있습니다. 특히 사용자 공간 프로세스가 네트워크 네임스페이스에 연결된 후 TAP/TUN 네트워크 인터페이스가 네트워크 네임스페이스 내에서 이동하는 경우에 문제가 있습니다. 여기에는 tapclient
간단한 변형이 있습니다 .a34729t의tunclient.c
, 탭 네트워크 이름을 수락하고 추가합니다):
$ sudo ip tuntap add tap123 mode tap
$ sudo tapclient tap123 &
$ sudo ip netns add fooz
$ sudo ip link set tap123 netns fooz
$ PID=$(ps faux | grep tapclient | grep -v -e sudo -e grep | awk '{print $2}')
$ sudo cat /proc/$PID/fdinfo/3
...그런 다음 다음을 제공합니다. iff: tap123
-- 그러나 tap123
네트워크 인터페이스가 현재 위치한 네트워크 네임스페이스는 아닙니다.
물론 tap123
모든 네트워크 네임스페이스를 반복하고 그 중 하나에서 일치하는 네트워크 인터페이스를 찾아 이를 찾을 수 있습니다. 불행하게도 tap123
첫 번째 이름을 위의 네트워크 네임스페이스로 이동한 fooz
후 호스트 네임스페이스에 다른 이름을 생성하는 경우와 같이 중복된 이름이 있을 수 있습니다 .
$ sudo ip tuntap add tap123 mode tap
$ ip link show tap123
$ sudo ip netns exec fooz ip link show tap123
그래서 우리는 지금둘 tap123
는 별도의 네트워크 네임스페이스에 있으며 fdinfo
모호한 iff: tap123
.
안타깝게도 Tapclient의 네트워크 네임스페이스를 살펴보는 것도 /proc/$PID/ns/net
도움이 되지 않습니다. 현재 네트워크 네임스페이스와 더 이상 일치하지 않기 때문입니다 tap123
.
$ findmnt -t nsfs | grep /run/netns/fooz
$ sudo readlink /proc/$PID/ns/net
예를 들어 , 이것은 net:[4026532591]
vs.net:[4026531993]
tapclient
프로세스가 연결된 올바른 네트워크 인터페이스 인스턴스와 명시적으로 일치시키는 방법이 있습니까 ?tap123
답변1
이름 대신 하드웨어 주소로 tun 인터페이스를 일치시킬 수 있습니다( ioctl(SIOCGIFHWADDR)
tun/tap 파일 설명자를 통해 주소를 얻을 수 있습니다).
이보다 더 간단한 것은 없다고 생각합니다. 그렇지 않으면 최근 변경 사항은 다음과 같습니다.이것(이렇게 하면 tun fd를 통해 인터페이스의 네트워크 네임스페이스를 검색하는 것이 필요하지 않고 허용될 가능성이 높아집니다.
답변2
불행히도 user313992의 팁 SIOCGSKNS
은 매우소켓에 유용함SIOCGSKNS
, TAP/TUN 파일 설명자의 구현은 다음과 같습니다.이상한: TAP/TUN이 원래 생성된 네트워크 네임스페이스의 fd를 반환하지만현재는 해당되지 않음netdev 네트워크 네임스페이스입니다.
더 둘러보세요__tun_chr_ioctl
구현된 경우 SIOCGSKNS
매우 유망한 것으로 나타났습니다.TUNGETDEVNETNS
ioctl 작업: 최종적으로 TAP/TUN 장치의 네트워크 네임스페이스를 얻고 반환합니다.
다음 단위 테스트 코드는 초기 네트워크 네임스페이스에 TAP 장치를 생성하고, 새 네트워크 네임스페이스를 생성한 다음, TAP netdev를 이 새 네트워크 네임스페이스로 이동합니다. 그런 다음 ioctl은 TUNGETDEVNETNS
TAP netdev가 이동된 새 네트워크 네임스페이스를 참조하는 fd를 올바르게 반환합니다.
package main
import (
"os"
"runtime"
"github.com/thediveo/notwork/link"
"github.com/thediveo/notwork/netns"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/thediveo/success"
)
const tapNamePrefix = "tap-"
// Ugly IOCTL stuff; copied from github.com/thediveo/lxkns/ops/ioctl.go
const _IOC_NRBITS = 8
const _IOC_TYPEBITS = 8
const _IOC_SIZEBITS = 14
const _IOC_NRSHIFT = 0
const _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
const _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
const _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
const _IOC_NONE = uint(0)
func _IOC(dir, ioctype, nr, size uint) uint {
return (dir << _IOC_DIRSHIFT) | (ioctype << _IOC_TYPESHIFT) | (nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT)
}
func _IO(ioctype, nr uint) uint {
return _IOC(_IOC_NONE, ioctype, nr, 0)
}
func getTapNetdevNetnsFd(fd int) (int, error) {
return unix.IoctlRetInt(fd, _IO('T', 227))
}
var _ = Describe("TAP/TUN netns", func() {
It("finds namespace of TAP/TUN netdev", func() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
By("creating a TAP netdev")
tt := netlink.Tuntap{
Mode: netlink.TUNTAP_MODE_TAP,
Queues: 1,
}
tap := link.NewTransient(&tt, tapNamePrefix).(*netlink.Tuntap)
Expect(tap.Fds).NotTo(BeEmpty())
for _, fd := range tap.Fds {
DeferCleanup(func() { fd.Close() })
}
By("creating a new transient network namespace")
newnetnsfd := netns.NewTransient()
By("moving the TAP netdev into the new network namespace")
Expect(netlink.LinkSetNsFd(tap, newnetnsfd)).To(Succeed())
Expect(netlink.LinkList()).NotTo(ContainElement(
HaveField("Attrs().Name", tap.Name)))
nlh := netns.NewNetlinkHandle(newnetnsfd)
defer func() {
Expect(nlh.LinkSetNsPid(tap, os.Getpid())).To(Succeed())
nlh.Close()
}()
Expect(nlh.LinkList()).To(ContainElement(
HaveField("Attrs().Name", tap.Name)))
By("querying the network namespace of the TAP netdev")
tapnetnsfd := Successful(getTapNetdevNetnsFd(int(tap.Fds[0].Fd())))
defer unix.Close(tapnetnsfd)
Expect(netns.Ino(tapnetnsfd)).NotTo(Equal(netns.CurrentIno()))
Expect(netns.Ino(tapnetnsfd)).To(Equal(netns.Ino(newnetnsfd)))
})
})