From 93e2d163ed066e940d87c324fa5b793b286df7a1 Mon Sep 17 00:00:00 2001 From: mame82 Date: Thu, 3 May 2018 16:09:53 +0000 Subject: [PATCH] Added bridge interface creation, USB gadget state parsing over RPC, some refinements --- P4wnP1_client_cli/cli_client.go | 14 ++- build_proto.sh => b_proto.sh | 0 core/network.go | 51 +++++++++ core/rpcsrv.go | 30 ++--- core/usb.go | 196 +++++++++++++++++++++++++++++++- dependencies.sh | 30 +++++ service.go | 9 ++ 7 files changed, 305 insertions(+), 25 deletions(-) rename build_proto.sh => b_proto.sh (100%) create mode 100644 core/network.go create mode 100755 dependencies.sh diff --git a/P4wnP1_client_cli/cli_client.go b/P4wnP1_client_cli/cli_client.go index 9f2258b..a7436f0 100644 --- a/P4wnP1_client_cli/cli_client.go +++ b/P4wnP1_client_cli/cli_client.go @@ -9,10 +9,12 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" pb "../proto" + "reflect" ) func main() { //Parse cli flags, should be replaced with cobra + getUsbGadgetConf := flag.Bool("get_gadget_state", false, "Retrieves the current USB gadget state") blinkCountPtr := flag.Int("blink", -1, "LED blink count (0 = LED off, 255 = LED solid, 1..254 blink n times)") var rpcHostPtr string var rpcPortPtr string @@ -36,9 +38,19 @@ func main() { defer cancel() if *blinkCountPtr >= 0 { - c.SetLEDSettings(ctx, &pb.LEDSettings{ BlinkCount: uint32(*blinkCountPtr) }) + _, err1 := c.SetLEDSettings(ctx, &pb.LEDSettings{BlinkCount: uint32(*blinkCountPtr)}) + if err1 != nil { + log.Printf("Error setting LED blink count %d: %v", *blinkCountPtr, err1) + } } + if *getUsbGadgetConf { + r, err := c.GetGadgetSettings(ctx, &pb.Empty{}) + if err != nil { + log.Fatalf("could not get GadgetSettings: %v", err) + } + log.Printf("USB Settings %s: %+v", reflect.TypeOf(*r), *r) + } /* r, err := c.GetGadgetSettings(ctx, &pb.Empty{}) diff --git a/build_proto.sh b/b_proto.sh similarity index 100% rename from build_proto.sh rename to b_proto.sh diff --git a/core/network.go b/core/network.go new file mode 100644 index 0000000..b14b6ec --- /dev/null +++ b/core/network.go @@ -0,0 +1,51 @@ +package core + +import ( + "github.com/docker/libcontainer/netlink" + "net" + "log" +) + +func CreateBridge(name string) error { + return netlink.CreateBridge(name, false) +} + +func DeleteBridge(name string) error { + return netlink.DeleteBridge(name) +} + +func CheckInterfaceExistence(name string) (res bool, err error) { + _, err = net.InterfaceByName(name) + if err != nil { + return false, err + } + return true, err +} + +func NetworkLinkUp(name string) (err error) { + iface, err := net.InterfaceByName(name) + if err != nil { + return err + } + + err = netlink.NetworkLinkUp(iface) + return +} + +func AddInterfaceToBridgeIfExistent(bridgeName string, ifName string) (err error) { + br, err := net.InterfaceByName(bridgeName) + if err != nil { + return err + } + iface, err := net.InterfaceByName(ifName) + if err != nil { + return err + } + + err = netlink.AddToBridge(iface, br) + if err != nil { + return err + } + log.Printf("Interface %s added to bridge %s", ifName, bridgeName) + return nil +} \ No newline at end of file diff --git a/core/rpcsrv.go b/core/rpcsrv.go index caf2897..8d6a089 100644 --- a/core/rpcsrv.go +++ b/core/rpcsrv.go @@ -15,28 +15,18 @@ import ( type server struct{} //Attach handler function implementing the "GetGadgetSettings" interface to server -func (s *server) GetGadgetSettings(context.Context, *pb.Empty) (*pb.GadgetSettings, error) { - usbset := &pb.GadgetSettings{ - Pid: "0x1337", - Vid: "0x1222", - Manufacturer: "MaMe82", - Serial: "deadbeef13371337", - Product: "P4wnP1 by MaMe82", - Use_RNDIS: false, - Use_CDC_ECM: true, - Use_HID_KEYBOARD: false, - Use_HID_MOUSE: false, - Use_HID_RAW: false, - Use_UMS: false, - Use_SERIAL: false, +func (s *server) GetGadgetSettings(context.Context, *pb.Empty) (usbset *pb.GadgetSettings, err error) { + usbset, err = ParseGadgetState(USB_GADGET_NAME) - RndisSettings: &pb.GadgetSettingsEthernet{HostAddr: "11:22:33:44:55:66", DevAddr: "66:55:44:33:22:11"}, - CdcEcmSettings: &pb.GadgetSettingsEthernet{HostAddr: "11:22:33:54:76:98", DevAddr: "66:55:44:98:76:54"}, + if err == nil { + j_usbset, _ := json.Marshal(usbset) + log.Printf("Gadget settings requested %v", string(j_usbset)) + } else { + log.Printf("Error parsing current gadget config: %v", err) } - j_usbset, _ := json.Marshal(usbset) - log.Printf("Gadget settings requested %v", string(j_usbset)) - return usbset, nil + + return usbset, err } //Attach handler function implementing the "SetGadgetSettings" interface to server @@ -68,7 +58,7 @@ func (s *server) SetLEDSettings(ctx context.Context, ledSettings *pb.LEDSettings func StartRpcServer(host string, port string) { listen_address := host + ":" + port //Open TCP listener - log.Printf("P4wnP1 RPC server lsitening on " + listen_address) + log.Printf("P4wnP1 RPC server listening on " + listen_address) lis, err := net.Listen("tcp", listen_address) if err != nil { log.Fatalf("failed to listen: %v", err) diff --git a/core/usb.go b/core/usb.go index c540e43..6c8817d 100644 --- a/core/usb.go +++ b/core/usb.go @@ -9,14 +9,16 @@ import ( "strings" pb "../proto" + "time" + "fmt" ) const ( + USB_GADGET_NAME = "mame82_gadget" USB_GADGET_DIR_BASE = "/sys/kernel/config/usb_gadget" - USB_GADGET_DIR = USB_GADGET_DIR_BASE + "/mame82_gadget" - USB_DEFAULT_SERIAL = "deadbeefdeadbeef" - USB_DEFAULT_MANUFACTURER = "MaMe82" - USB_DEFAULT_PRODUCT = "P4wnP1 by MaMe82" + USB_GADGET_DIR = USB_GADGET_DIR_BASE + "/" + USB_GADGET_NAME + + USB_ETHERNET_BRIDGE_NAME = "usbeth" USB_bcdDevice = "0x0100" //Version 1.00 USB_bcdUSB = "0x0200" //mode: USB 2.0 @@ -69,6 +71,47 @@ const ( USB_FUNCTION_HID_RAW_name = "hid.raw" ) +func addUSBEthernetBridge() { + //Create the bridge + CreateBridge(USB_ETHERNET_BRIDGE_NAME) + + //add the interfaces + if err := AddInterfaceToBridgeIfExistent(USB_ETHERNET_BRIDGE_NAME, "usb0"); err != nil { + log.Println(err) + } + if err := AddInterfaceToBridgeIfExistent(USB_ETHERNET_BRIDGE_NAME, "usb1"); err != nil { + log.Println(err) + } + + //enable the bridge + NetworkLinkUp(USB_ETHERNET_BRIDGE_NAME) +} + +func deleteUSBEthernetBridge() { + //we ignore error results + DeleteBridge(USB_ETHERNET_BRIDGE_NAME) +} + +/* +Polls for presence of "usb0" / "usb1" till one of both is active or timeout is reached + */ + +func pollForUSBEthrnet(timeout time.Duration) error { + for startTime := time.Now(); time.Since(startTime) < timeout; { + if present, _ := CheckInterfaceExistence("usb0"); present { + return nil + } + if present, _ := CheckInterfaceExistence("usb1"); present { + return nil + } + + //Take a breath + time.Sleep(100*time.Millisecond) + fmt.Print(".") + } + return errors.New(fmt.Sprintf("Timeout %v reached before usb0 or usb1 cam up")) +} + func InitDefaultGadgetSettings() error { return InitGadget(CreateDefaultGadgetSettings()) } @@ -123,7 +166,125 @@ func CheckLibComposite() error { return err } +func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error) { + err = nil + result = &pb.GadgetSettings{} + result.CdcEcmSettings = &pb.GadgetSettingsEthernet{} + result.RndisSettings = &pb.GadgetSettingsEthernet{} + + //gadget_root := "./test" + gadget_dir := USB_GADGET_DIR_BASE + "/" + gadgetName + + //check if root exists, return error otherwise + if _, err = os.Stat(gadget_dir); os.IsNotExist(err) { + err = errors.New(fmt.Sprintf("Gadget %s doesn't exist", gadgetName)) + result = nil + return + } + + if res, err := ioutil.ReadFile(gadget_dir + "/idVendor"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading Vid", gadgetName)) + return nil, err1 + } else { + result.Vid = strings.TrimSuffix(string(res), "\n") + } + + if res, err := ioutil.ReadFile(gadget_dir + "/idProduct"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading Pid", gadgetName)) + return nil, err1 + } else { + result.Pid = strings.TrimSuffix(string(res), "\n") + } + + if res, err := ioutil.ReadFile(gadget_dir + "/strings/0x409/serialnumber"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading Serial", gadgetName)) + return nil, err1 + } else { + result.Serial = strings.TrimSuffix(string(res), "\n") + } + + if res, err := ioutil.ReadFile(gadget_dir + "/strings/0x409/manufacturer"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading Manufacturer", gadgetName)) + return nil, err1 + } else { + result.Manufacturer = strings.TrimSuffix(string(res), "\n") + } + + if res, err := ioutil.ReadFile(gadget_dir + "/strings/0x409/product"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading Product", gadgetName)) + return nil, err1 + } else { + result.Product = strings.TrimSuffix(string(res), "\n") + } + + //Check enabled functions in configuration + + //USB RNDIS + if _, err1 := os.Stat(gadget_dir+"/configs/c.1/rndis.usb0"); !os.IsNotExist(err1) { + result.Use_RNDIS = true + + if res, err := ioutil.ReadFile(gadget_dir + "/functions/rndis.usb0/host_addr"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading RNDIS host_addr", gadgetName)) + return nil, err1 + } else { + result.RndisSettings.HostAddr = strings.TrimSuffix(string(res), "\000\n") + } + + if res, err := ioutil.ReadFile(gadget_dir + "/functions/rndis.usb0/dev_addr"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading RNDIS dev_addr", gadgetName)) + return nil, err1 + } else { + result.RndisSettings.DevAddr = strings.TrimSuffix(string(res), "\000\n") + } + } + + //USB CDC ECM + if _, err1 := os.Stat(gadget_dir+"/configs/c.1/ecm.usb1"); !os.IsNotExist(err1) { + result.Use_CDC_ECM = true + + if res, err := ioutil.ReadFile(gadget_dir + "/functions/ecm.usb1/host_addr"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading CDC ECM host_addr", gadgetName)) + return nil, err1 + } else { + result.CdcEcmSettings.HostAddr = strings.TrimSuffix(string(res), "\000\n") + } + + if res, err := ioutil.ReadFile(gadget_dir + "/functions/ecm.usb1/dev_addr"); err != nil { + err1 := errors.New(fmt.Sprintf("Gadget %s error reading CDC ECM dev_addr", gadgetName)) + return nil, err1 + } else { + result.CdcEcmSettings.DevAddr = strings.TrimSuffix(string(res), "\000\n") + } + + } + + //USB serial + if _, err1 := os.Stat(gadget_dir+"/configs/c.1/acm.GS0"); !os.IsNotExist(err1) { + result.Use_SERIAL = true + } + + //USB HID Keyboard + if _, err1 := os.Stat(gadget_dir+"/configs/c.1/"+USB_FUNCTION_HID_KEYBOARD_name); !os.IsNotExist(err1) { + result.Use_HID_KEYBOARD = true + } + + //USB HID Mouse + if _, err1 := os.Stat(gadget_dir+"/configs/c.1/"+USB_FUNCTION_HID_MOUSE_name); !os.IsNotExist(err1) { + result.Use_HID_KEYBOARD = true + } + + //USB HID RAW + if _, err1 := os.Stat(gadget_dir+"/configs/c.1/"+USB_FUNCTION_HID_RAW_name); !os.IsNotExist(err1) { + result.Use_HID_RAW = true + } + + return + +} + func InitGadget(settings pb.GadgetSettings) error { + var usesUSBEthernet bool + //gadget_root := "./test" gadget_root := USB_GADGET_DIR_BASE @@ -136,6 +297,8 @@ func InitGadget(settings pb.GadgetSettings) error { //create gadget folder os.Mkdir(USB_GADGET_DIR, os.ModePerm) + log.Printf("Creating composite gadget '%s'", USB_GADGET_NAME) + //set vendor ID, product ID ioutil.WriteFile(USB_GADGET_DIR+"/idVendor", []byte(settings.Vid), os.ModePerm) ioutil.WriteFile(USB_GADGET_DIR+"/idProduct", []byte(settings.Pid), os.ModePerm) @@ -163,6 +326,8 @@ func InitGadget(settings pb.GadgetSettings) error { // RNDIS has to be the first interface on Composite device for Windows (first function initialized) if settings.Use_RNDIS { + log.Printf("... creating USB RNDIS function") + usesUSBEthernet = true os.Mkdir(USB_GADGET_DIR+"/functions/rndis.usb0", os.ModePerm) //create RNDIS function ioutil.WriteFile(USB_GADGET_DIR+"/functions/rndis.usb0/host_addr", []byte(settings.RndisSettings.HostAddr), os.ModePerm) ioutil.WriteFile(USB_GADGET_DIR+"/functions/rndis.usb0/dev_addr", []byte(settings.RndisSettings.DevAddr), os.ModePerm) @@ -205,6 +370,8 @@ func InitGadget(settings pb.GadgetSettings) error { } if settings.Use_CDC_ECM { + log.Printf("... creating USB CDC ECM function") + usesUSBEthernet = true os.Mkdir(USB_GADGET_DIR+"/functions/ecm.usb1", os.ModePerm) //create CDC ECM function ioutil.WriteFile(USB_GADGET_DIR+"/functions/ecm.usb1/host_addr", []byte(settings.CdcEcmSettings.HostAddr), os.ModePerm) ioutil.WriteFile(USB_GADGET_DIR+"/functions/ecm.usb1/dev_addr", []byte(settings.CdcEcmSettings.DevAddr), os.ModePerm) @@ -217,6 +384,7 @@ func InitGadget(settings pb.GadgetSettings) error { } if settings.Use_SERIAL { + log.Printf("... creating USB serial function") os.Mkdir(USB_GADGET_DIR+"/functions/acm.GS0", os.ModePerm) //create ACM function //activate function by symlinking to config 1 @@ -228,6 +396,7 @@ func InitGadget(settings pb.GadgetSettings) error { } if settings.Use_HID_KEYBOARD { + log.Printf("... creating USB HID Keyboard function") funcdir := USB_GADGET_DIR + "/functions/" + USB_FUNCTION_HID_KEYBOARD_name os.Mkdir(funcdir, os.ModePerm) //create HID function for keyboard @@ -243,6 +412,7 @@ func InitGadget(settings pb.GadgetSettings) error { } if settings.Use_HID_MOUSE { + log.Printf("... creating USB HID Mouse function") funcdir := USB_GADGET_DIR + "/functions/" + USB_FUNCTION_HID_MOUSE_name os.Mkdir(funcdir, os.ModePerm) //create HID function for mouse @@ -258,6 +428,7 @@ func InitGadget(settings pb.GadgetSettings) error { } if settings.Use_HID_RAW { + log.Printf("... creating USB HID Generic device function") funcdir := USB_GADGET_DIR + "/functions/" + USB_FUNCTION_HID_RAW_name os.Mkdir(funcdir, os.ModePerm) //create HID function for mouse @@ -283,6 +454,23 @@ func InitGadget(settings pb.GadgetSettings) error { udc_name := files[0].Name() ioutil.WriteFile(USB_GADGET_DIR+"/UDC", []byte(udc_name), os.ModePerm) + + deleteUSBEthernetBridge() //delete former used bridge, if there's any + //In case USB ethernet is uesd (RNDIS or CDC ECM), we add a bridge interface + if usesUSBEthernet { + //wait till "usb0" or "usb1" comes up + err = pollForUSBEthrnet(10*time.Second) + if err == nil { + //add USBEthernet bridge including the usb interfaces + log.Printf("... creating network bridge for USB ethernet devices") + addUSBEthernetBridge() + } else { + return err + } + + } + + log.Printf("... done") return nil } diff --git a/dependencies.sh b/dependencies.sh new file mode 100755 index 0000000..4d737cb --- /dev/null +++ b/dependencies.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# install dependencies +# - dnsmasq for DHCP / DNS server +# - bridge-utils for bonding CDC ECM + RNDIS interface toa single bridge +# - hostapd for AP deployment +# - screen to attach interactive processes to a detachable tty +# - autossh for "reachback" SSH connections +# - bluez (bluez-bleutooth, policykit-1) for access to Bluetooth / BLE stack (depends on DBUS systemd service) +# - haveged as entropy daemon to get enough entropy for hostapd AP with WPA2 +# - iodine for DNS tunnel capbilities +# - genisoimage to allow on-the-fly CD-Rom image creation for CD emulation + +sudo apt-get -y install git screen hostapd autossh bluez bluez-tools bridge-utils policykit-1 genisoimage iodine haveged +sudo apt-get -y install tcpdump +sudo apt-get -y install python-pip python-dev + +# before installing dnsmasq, the nameserver from /etc/resolv.conf should be saved +# to restore after install (gets overwritten by dnsmasq package) +cp /etc/resolv.conf /tmp/backup_resolv.conf +sudo apt-get -y install dnsmasq +sudo /bin/bash -c 'cat /tmp/backup_resolv.conf > /etc/resolv.conf' + + + +# python dependencies for HIDbackdoor +sudo pip install pycrypto # already present on stretch +sudo pip install pydispatcher + + diff --git a/service.go b/service.go index 5f54fc1..dc4267e 100644 --- a/service.go +++ b/service.go @@ -7,6 +7,14 @@ import ( ) func main() { + /* + if gadget, err := core.ParseGadgetState(core.USB_GADGET_NAME); err == nil { + log.Printf("Gadget config: %+v", gadget) + } else { + log.Printf("Gadget %s couldn't be parsed: %s", core.USB_GADGET_NAME, err) + } + */ + var err error err = core.CheckLibComposite() if err != nil { @@ -23,6 +31,7 @@ func main() { log.Fatalf("Error while setting up the default gadget: %v", err) } + core.InitLed(false) //Set LED to manual triger //core.StartRpcServer("127.0.0.1", "50051") //start gRPC service core.StartRpcServer("", "50051") //start gRPC service