add captured: sends packets to Wireshark SSH remote capture
Just point your wireshark to 10.0.0.1:5022.
This commit is contained in:
parent
8b85084429
commit
bb563e0798
39
cmd/captured/GENERATED_filterexpr.go
Normal file
39
cmd/captured/GENERATED_filterexpr.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "golang.org/x/net/bpf"
|
||||||
|
|
||||||
|
var instructions = []bpf.RawInstruction{
|
||||||
|
{40, 0, 0, 12},
|
||||||
|
{21, 0, 13, 34525},
|
||||||
|
{48, 0, 0, 20},
|
||||||
|
{21, 27, 0, 58},
|
||||||
|
{21, 0, 2, 44},
|
||||||
|
{48, 0, 0, 54},
|
||||||
|
{21, 24, 25, 58},
|
||||||
|
{21, 0, 24, 17},
|
||||||
|
{40, 0, 0, 54},
|
||||||
|
{21, 21, 0, 67},
|
||||||
|
{21, 20, 0, 68},
|
||||||
|
{21, 19, 0, 546},
|
||||||
|
{21, 18, 0, 547},
|
||||||
|
{40, 0, 0, 56},
|
||||||
|
{21, 16, 13, 67},
|
||||||
|
{21, 0, 16, 2048},
|
||||||
|
{48, 0, 0, 23},
|
||||||
|
{21, 0, 14, 17},
|
||||||
|
{40, 0, 0, 20},
|
||||||
|
{69, 12, 0, 8191},
|
||||||
|
{177, 0, 0, 14},
|
||||||
|
{72, 0, 0, 14},
|
||||||
|
{21, 8, 0, 67},
|
||||||
|
{21, 7, 0, 68},
|
||||||
|
{21, 6, 0, 546},
|
||||||
|
{21, 5, 0, 547},
|
||||||
|
{72, 0, 0, 16},
|
||||||
|
{21, 3, 0, 67},
|
||||||
|
{21, 2, 0, 68},
|
||||||
|
{21, 1, 0, 546},
|
||||||
|
{21, 0, 1, 547},
|
||||||
|
{6, 0, 0, 1500},
|
||||||
|
{6, 0, 0, 0},
|
||||||
|
}
|
23
cmd/captured/captured.go
Normal file
23
cmd/captured/captured.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
hostKeyPath = flag.String("host_key",
|
||||||
|
"/perm/breakglass.host_key",
|
||||||
|
"path to a PEM-encoded RSA, DSA or ECDSA private key (create using e.g. ssh-keygen -f /perm/breakglass.host_key -N '' -t rsa)")
|
||||||
|
)
|
||||||
|
|
||||||
|
func logic() error {
|
||||||
|
return listenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
if err := logic(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
49
cmd/captured/filterexpr.go
Normal file
49
cmd/captured/filterexpr.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
"github.com/google/gopacket/pcap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// udp and (port 67 or port 68) # dhcpv4
|
||||||
|
// udp and (port 546 or port 547) # dhcpv6
|
||||||
|
// icmp6 # router|neighbor solicitation|announcement
|
||||||
|
const expression = `icmp6 or (udp and (port 67 or port 68 or port 546 or port 547))`
|
||||||
|
|
||||||
|
func gen(w io.Writer) error {
|
||||||
|
fmt.Fprintf(w, "package main\n")
|
||||||
|
instructions, err := pcap.CompileBPFFilter(layers.LinkTypeEthernet, 1500, expression)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "import %q\n", "golang.org/x/net/bpf")
|
||||||
|
fmt.Fprintf(w, "var instructions = []bpf.RawInstruction{\n")
|
||||||
|
for _, inst := range instructions {
|
||||||
|
fmt.Fprintf(w, "{%d, %d, %d, %d},\n", inst.Code, inst.Jt, inst.Jf, inst.K)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "}")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
if err := gen(&buffer); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
gofmt, err := format.Source(buffer.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile("GENERATED_filterexpr.go", gofmt, 0644); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
3
cmd/captured/genfilterexpr.go
Normal file
3
cmd/captured/genfilterexpr.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
//go:generate go run filterexpr.go
|
170
cmd/captured/ssh.go
Normal file
170
cmd/captured/ssh.go
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/gokrazy/gokrazy"
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
"github.com/google/gopacket/pcapgo"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleChannel(newChannel ssh.NewChannel) {
|
||||||
|
if t := newChannel.ChannelType(); t != "session" {
|
||||||
|
newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %q", t))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, requests, err := newChannel.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Could not accept channel (%s)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sessions have out-of-band requests such as "shell", "pty-req" and "env"
|
||||||
|
go func(channel ssh.Channel, requests <-chan *ssh.Request) {
|
||||||
|
s := session{channel: channel}
|
||||||
|
for req := range requests {
|
||||||
|
if err := s.request(req); err != nil {
|
||||||
|
errmsg := []byte(err.Error())
|
||||||
|
// Append a trailing newline; the error message is
|
||||||
|
// displayed as-is by ssh(1).
|
||||||
|
if errmsg[len(errmsg)-1] != '\n' {
|
||||||
|
errmsg = append(errmsg, '\n')
|
||||||
|
}
|
||||||
|
req.Reply(false, errmsg)
|
||||||
|
channel.Write(errmsg)
|
||||||
|
channel.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(channel, requests)
|
||||||
|
}
|
||||||
|
|
||||||
|
type session struct {
|
||||||
|
channel ssh.Channel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) request(req *ssh.Request) error {
|
||||||
|
switch req.Type {
|
||||||
|
case "exec":
|
||||||
|
if got, want := len(req.Payload), 4; got < want {
|
||||||
|
return fmt.Errorf("exec request payload too short: got %d, want >= %d", got, want)
|
||||||
|
}
|
||||||
|
log.Printf("exec, wantReply %v, payload %q", req.WantReply, string(req.Payload[4:]))
|
||||||
|
|
||||||
|
pcapw := pcapgo.NewWriter(s.channel)
|
||||||
|
if err := pcapw.WriteFileHeader(1600, layers.LinkTypeEthernet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
packets := make(chan gopacket.Packet)
|
||||||
|
for _, ifname := range []string{"uplink0", "lan0"} {
|
||||||
|
handle, err := pcapgo.OpenEthernet(ifname)
|
||||||
|
//handle, err := pcap.OpenLive("uplink0", 1600, false /* promisc */, pcap.BlockForever)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := handle.SetBPF(instructions); err != nil {
|
||||||
|
//if err := handle.SetBPFFilter("icmp6 or (udp and (port 67 or port 68 or port 546 or port 547))"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
|
||||||
|
go func() {
|
||||||
|
for packet := range pkgsrc.Packets() {
|
||||||
|
packets <- packet
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Reply(true, nil)
|
||||||
|
|
||||||
|
for packet := range packets {
|
||||||
|
log.Printf("packet: %+v", packet)
|
||||||
|
if err := pcapw.WritePacket(packet.Metadata().CaptureInfo, packet.Data()); err != nil {
|
||||||
|
return fmt.Errorf("pcap.WritePacket(): %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown request type: %q", req.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadHostKey(path string) (ssh.Signer, error) {
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssh.ParsePrivateKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listenAndServe() error {
|
||||||
|
config := &ssh.ServerConfig{
|
||||||
|
PublicKeyCallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
|
return nil, nil // authorize all users
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
signer, err := loadHostKey(*hostKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.AddHostKey(signer)
|
||||||
|
|
||||||
|
accept := func(listener net.Listener) {
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("accept: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(conn net.Conn) {
|
||||||
|
_, chans, reqs, err := ssh.NewServerConn(conn, config)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("handshake: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// discard all out of band requests
|
||||||
|
go ssh.DiscardRequests(reqs)
|
||||||
|
|
||||||
|
for newChannel := range chans {
|
||||||
|
handleChannel(newChannel)
|
||||||
|
}
|
||||||
|
}(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := gokrazy.PrivateInterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
hostport := net.JoinHostPort(addr, "5022")
|
||||||
|
listener, err := net.Listen("tcp", hostport)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("listening on %s\n", hostport)
|
||||||
|
go accept(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("host key fingerprint: %s\n", ssh.FingerprintSHA256(signer.PublicKey()))
|
||||||
|
|
||||||
|
select {}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user