Added bridge interface creation, USB gadget state parsing over RPC, some refinements

This commit is contained in:
mame82 2018-05-03 16:09:53 +00:00
parent 3a9ec59b18
commit 93e2d163ed
7 changed files with 305 additions and 25 deletions

View File

@ -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{})

51
core/network.go Normal file
View File

@ -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
}

View File

@ -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)

View File

@ -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
}

30
dependencies.sh Executable file
View File

@ -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

View File

@ -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