Skip to content

Commit

Permalink
iOS17 Linux Driver (#334)
Browse files Browse the repository at this point in the history
* add cdc-ncm user space driver for Linux

---------

Co-authored-by: dmissmann <[email protected]>
  • Loading branch information
danielpaulus and dmissmann authored Feb 14, 2024
1 parent ce74125 commit 7faba25
Show file tree
Hide file tree
Showing 12 changed files with 861 additions and 3 deletions.
14 changes: 11 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ jobs:
go-version-file: go.mod
cache: true

#- name: Install Libusb
# run: choco install

- name: Build executable
run: go build

- name: Run fast tests
run: go test -v -tags=fast ./...
#- name: Run fast tests
# run: go test -v -tags=fast ./...

test_on_linux:
runs-on: ubuntu-latest
Expand All @@ -30,9 +33,14 @@ jobs:
with:
go-version-file: go.mod
cache: true
- name: update
run: sudo apt-get update

- name: install libusb
run: sudo apt-get install -y libusb-1.0-0-dev

- name: Build executable
run: go build
run: make build --trace

- name: Run fast tests
run: go test -v -tags=fast ./...
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ devimages
go-ios
usbmuxd
main
go-ncm
*.png
!logo.png
# Test binary, build with `go test -c`
Expand Down
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Makefile to build and run go-ios and the cdc-ncm network driver
# cdc-ncm needs to be executed with sudo on Linux for USB Access and setting
# up virtual TAP network devices.
# use Make build to build both binaries.
# Make run is a simple target that just runs the cdc-ncm driver with sudo
# For development, use "make up" to rebuild and run cdc-ncm quickly

# Name of your Go binaries
GO_IOS_BINARY_NAME=ios
NCM_BINARY_NAME=go-ncm

# Build the Go program
build:
@go work use .
@go build -o $(GO_IOS_BINARY_NAME) ./main.go
@go work use ./ncm
@go build -o $(NCM_BINARY_NAME) ./cmd/cdc-ncm/main.go

# Run the Go program with sudo
run: build
@sudo ./$(NCM_BINARY_NAME)

# Build and run
up: build run

# Phony targets
.PHONY: build run up
47 changes: 47 additions & 0 deletions cmd/cdc-ncm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
ncm "go-ios-cdcncm"
"log/slog"
"os"
"os/signal"
"runtime"
)

func checkRoot() {
u := os.Geteuid()
if u != 0 {
slog.Error("go-ncm needs root. run with sudo.")
os.Exit(1)
}
}

func checkLinux() {
if runtime.GOOS != "linux" {
slog.Error("go-ncm only works on linux")
os.Exit(1)
}
}

func main() {
checkLinux()
checkUsbMux()
checkRoot()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
err := ncm.Start(c)
if err != nil {
slog.Error("error looking for devices", slog.Any("error", err))
os.Exit(1)
}

}

func checkUsbMux() {
v, err := ncm.CheckUSBMUXVersion()
if err != nil {
slog.Error("error getting usbmuxd version", slog.Any("error", err))
os.Exit(1)
}
slog.Info("usbmuxd version", slog.Any("version", v))
}
6 changes: 6 additions & 0 deletions go.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go 1.21.4

use (
.
./ncm
)
15 changes: 15 additions & 0 deletions ncm/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module go-ios-cdcncm

go 1.21

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/gousb v1.1.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 // indirect
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
golang.org/x/sys v0.15.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
25 changes: 25 additions & 0 deletions ncm/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/gousb v1.1.2 h1:1BwarNB3inFTFhPgUEfah4hwOPuDz/49I0uX8XNginU=
github.com/google/gousb v1.1.2/go.mod h1:GGWUkK0gAXDzxhwrzetW592aOmkkqSGcj5KLEgmCVUg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w=
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY=
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
62 changes: 62 additions & 0 deletions ncm/linux_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ncm

import (
"fmt"
"os/exec"
"strings"

"github.com/Masterminds/semver"
)

// SetInterfaceUp uses the ubuntu command line to activate an ethernet device with interfaceName
func SetInterfaceUp(interfaceName string) (string, error) {
b, err := exec.Command("/bin/sh", "-c", fmt.Sprintf("ip link set dev %s up", interfaceName)).CombinedOutput()
return string(b), err
}

// AddInterface adds an ipv6 address to an interface using an ubuntu cmd line invocation
func AddInterface(interfaceName string, ipv6 string) (string, error) {
cmd := fmt.Sprintf("ip -6 addr add %s dev %s", ipv6, interfaceName)
b, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
return string(b), err
}

// InterfaceHasIP uses 'ip -6 addr show dev' to check existin ips
func InterfaceHasIP(interfaceName string) (bool, string) {
cmd := fmt.Sprintf("ip -6 addr show dev %s", interfaceName)
b, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
if err != nil {
return false, ""
}
output := string(b)
output = strings.TrimSpace(output)
if output == "" {
return false, output
}
return true, output
}

const lowestSupportedVersionString = "usbmuxd 1.1.1-56-g360619c"

var lowestSupportedVersion = semver.MustParse(strings.Replace(lowestSupportedVersionString, "usbmuxd ", "", -1))

// CheckUSBMUXVersion runs usbmuxd --version to make sure it is newer or equal to usbmuxd 1.1.1-56-g360619c
func CheckUSBMUXVersion() (*semver.Version, error) {
b, err := exec.Command("/bin/sh", "-c", "usbmuxd --version").CombinedOutput()
if err != nil {
return &semver.Version{}, err
}
version := strings.Replace(string(b), "usbmuxd ", "", -1)
version = strings.TrimSpace(version)
v, err := semver.NewVersion(version)
if err != nil {
return &semver.Version{}, fmt.Errorf("CheckUSBMUXVersion: could not parse usbmuxd version: %s from '%s'", err.Error(), string(b))
}
ok := v.Equal(lowestSupportedVersion) || v.GreaterThan(lowestSupportedVersion)

if !ok {
return v, fmt.Errorf("usbmuxd version %s is not supported. Please use at least %s", version, lowestSupportedVersion)
}

return v, nil
}
17 changes: 17 additions & 0 deletions ncm/linux_commands_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ncm

import (
"github.com/Masterminds/semver"
"github.com/stretchr/testify/assert"
"strings"
"testing"
)

func TestUsbmuxDVersion(t *testing.T) {
const usbmuxVersion = "usbmuxd 1.1.1-56-g360619c"
version := strings.Replace(usbmuxVersion, "usbmuxd ", "", -1)
v, err := semver.NewVersion(version)
assert.Nil(t, err)
ok := v.Equal(v) || v.GreaterThan(v)
print(ok)
}
Loading

0 comments on commit 7faba25

Please sign in to comment.