mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-04 04:56:16 +00:00
161 lines
3.5 KiB
Go
161 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"github.com/florianl/go-tc"
|
|
"github.com/florianl/go-tc/core"
|
|
"golang.zx2c4.com/wireguard/tun"
|
|
)
|
|
|
|
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cflags "-O2 -Iinclude" bpf bpf.c
|
|
|
|
func main() {
|
|
if err := run(); err != nil {
|
|
log.Fatal(err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
const (
|
|
divertInterface = "hack0"
|
|
tailscaleInterface = "tailscale0"
|
|
)
|
|
|
|
func run() error {
|
|
dev, err := tun.CreateTUN(divertInterface, 1280)
|
|
if err != nil {
|
|
return fmt.Errorf("creating tun: %v", err)
|
|
}
|
|
defer dev.Close()
|
|
|
|
divertIdx, err := ifIndex(divertInterface)
|
|
if err != nil {
|
|
return fmt.Errorf("getting index of divert interface: %v", err)
|
|
}
|
|
tailscaleIdx, err := ifIndex(tailscaleInterface)
|
|
if err != nil {
|
|
return fmt.Errorf("getting index of tailscale interface: %v", err)
|
|
}
|
|
|
|
// Prevent IPv6 link-local spam
|
|
if err := exec.Command("ip", "link", "set", divertInterface, "addrgenmode", "none").Run(); err != nil {
|
|
return fmt.Errorf("bringing up iface: %v", err)
|
|
}
|
|
if err := exec.Command("ip", "link", "set", divertInterface, "up").Run(); err != nil {
|
|
return fmt.Errorf("bringing up iface: %v", err)
|
|
}
|
|
|
|
spec, err := loadBpf()
|
|
if err != nil {
|
|
return fmt.Errorf("loading tailscale egress program: %v", err)
|
|
}
|
|
err = spec.RewriteConstants(map[string]interface{}{
|
|
"ifidx_divert": divertIdx,
|
|
"ifidx_tailscale": tailscaleIdx,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("setting interface ID: %v", err)
|
|
}
|
|
var objs bpfObjects
|
|
if err := spec.LoadAndAssign(&objs, nil); err != nil {
|
|
return fmt.Errorf("loading tailscale egress program: %v", err)
|
|
}
|
|
defer objs.Close()
|
|
|
|
tcnl, err := tc.Open(&tc.Config{})
|
|
if err != nil {
|
|
return fmt.Errorf("opening rtnetlink socket: %v", err)
|
|
}
|
|
defer tcnl.Close()
|
|
|
|
qdisc := tc.Object{
|
|
tc.Msg{
|
|
Ifindex: tailscaleIdx,
|
|
Handle: core.BuildHandle(tc.HandleIngress, 0),
|
|
Parent: tc.HandleIngress,
|
|
},
|
|
tc.Attribute{
|
|
Kind: "clsact",
|
|
},
|
|
}
|
|
if err := tcnl.Qdisc().Replace(&qdisc); err != nil {
|
|
return fmt.Errorf("adding/replacing clsact qdisc on tailscale interface: %v", err)
|
|
}
|
|
qdisc.Msg.Ifindex = divertIdx
|
|
if err := tcnl.Qdisc().Replace(&qdisc); err != nil {
|
|
return fmt.Errorf("adding/replacing clsact qdisc on divert interface: %v", err)
|
|
}
|
|
|
|
fd := uint32(objs.EgressTailscale.FD())
|
|
flags := uint32(1) // TCA_BPF_FLAG_ACT_DIRECT
|
|
handleEgress := uint32(0xFFFFFFF3)
|
|
name := "fucksake"
|
|
filter := &tc.Object{
|
|
tc.Msg{
|
|
Ifindex: tailscaleIdx,
|
|
Parent: handleEgress,
|
|
Handle: 1,
|
|
Info: 0x0300, // ETH_P_ALL, byteswapped into the lower 16 bits of info. Yeah, really.
|
|
},
|
|
tc.Attribute{
|
|
Kind: "bpf",
|
|
BPF: &tc.Bpf{
|
|
FD: &fd,
|
|
Name: &name,
|
|
Flags: &flags,
|
|
},
|
|
},
|
|
}
|
|
fmt.Println(fd)
|
|
if err := tcnl.Filter().Add(filter); err != nil {
|
|
return fmt.Errorf("adding/replacing tailscale egress filter: %v", err)
|
|
}
|
|
|
|
if err := dumpPackets(dev); err != nil {
|
|
return fmt.Errorf("reading packets: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ifIndex(name string) (uint32, error) {
|
|
intf, err := net.InterfaceByName(name)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return uint32(intf.Index), nil
|
|
}
|
|
|
|
func dumpPackets(dev tun.Device) error {
|
|
for {
|
|
var b [1284]byte
|
|
n, err := dev.Read(b[:], 4)
|
|
if err != nil {
|
|
return fmt.Errorf("reading from tun: %v", err)
|
|
}
|
|
|
|
bs := b[4 : 4+n]
|
|
|
|
fmt.Printf("received packet of %d bytes\n", len(bs))
|
|
hexdump(bs)
|
|
}
|
|
}
|
|
|
|
func hexdump(bs []byte) {
|
|
for i := range bs {
|
|
switch {
|
|
case i == 0:
|
|
case i%16 == 0:
|
|
fmt.Println("")
|
|
case i%8 == 0:
|
|
fmt.Printf(" ")
|
|
}
|
|
fmt.Printf("%02x ", bs[i])
|
|
}
|
|
fmt.Printf("\n\n")
|
|
}
|