Skip to content

Commit 4b68c81

Browse files
committed
Now uses time.After, and both lazy and mac have a timeout now
1 parent cef9074 commit 4b68c81

File tree

2 files changed

+80
-88
lines changed

2 files changed

+80
-88
lines changed

ios/pcap/ipfinder.go

+65-78
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package pcap
22

33
import (
44
"fmt"
5+
"io"
56
"time"
67

78
"github.com/danielpaulus/go-ios/ios"
@@ -29,33 +30,36 @@ func (n PacketInfo) complete() bool {
2930
// FindIPByMac reads pcap packets until one is found that matches the given MAC
3031
// and contains an IP address. This won't work if the iOS device "automatic Wifi address" privacy
3132
// feature is enabled. The MAC needs to be static.
32-
func FindIPByMac(device ios.DeviceEntry) (NetworkInfo, error) {
33+
func FindIPByMac(device ios.DeviceEntry, capture_timeout time.Duration) (NetworkInfo, error) {
3334
mac, err := ios.GetWifiMac(device)
3435
if err != nil {
3536
return NetworkInfo{}, fmt.Errorf("FindIPMyMac: unable to get WiFi MAC Address: %w", err)
3637
}
3738

38-
// channel to receive PacketInfo
39-
c := make(chan PacketInfo)
40-
done := make(chan bool)
41-
captureError := make(chan error)
42-
43-
go func() {
44-
captureError <- startCapture(device, c, done)
45-
}()
46-
47-
// captureDuration := time.Duration(10 * time.Second)
48-
// startTime := time.Now()
49-
for packet := range c {
50-
if packet.Mac == mac {
51-
done <- true
52-
return NetworkInfo{Mac: packet.Mac, IPv4: packet.IPv4, IPv6: packet.IPv6}, nil
53-
}
39+
log.Infof("FindIPByMac: connected to pcapd. timeout %v", capture_timeout)
40+
41+
pcapService, err := ios.ConnectToService(device, "com.apple.pcapd")
42+
if err != nil {
43+
return NetworkInfo{}, fmt.Errorf("FindIPByMac: failed connecting to com.apple.pcapd with err: %w", err)
5444
}
5545

56-
captureErrorResult := <-captureError
57-
if captureErrorResult != nil {
58-
return NetworkInfo{}, fmt.Errorf("FindIPByMac: failed to startCapture got err: %w", captureErrorResult)
46+
endSignal := time.After(capture_timeout)
47+
48+
L:
49+
for {
50+
select {
51+
case <-endSignal:
52+
break L
53+
default:
54+
packet, err := readPacket(pcapService.Reader())
55+
if err != nil {
56+
return NetworkInfo{}, fmt.Errorf("FindIPByMac: error reading pcap packet: %w", err)
57+
}
58+
59+
if packet.Mac == mac {
60+
return NetworkInfo{Mac: packet.Mac, IPv4: packet.IPv4, IPv6: packet.IPv6}, nil
61+
}
62+
}
5963
}
6064

6165
return NetworkInfo{}, fmt.Errorf("failed to get any IP matching the MAC: %s", mac)
@@ -67,36 +71,35 @@ func FindIPByMac(device ios.DeviceEntry) (NetworkInfo, error) {
6771
// If the device only contains a single IP, then it would be 50/50 which IP will be returned.
6872
// This is best effort! It's important to generate some traffic, when this function runs to get better results.
6973
func FindIPByLazy(device ios.DeviceEntry, capture_duration time.Duration) (NetworkInfo, error) {
70-
// channel to receive PacketInfo
71-
c := make(chan PacketInfo)
72-
done := make(chan bool)
73-
captureError := make(chan error)
74+
pcapService, err := ios.ConnectToService(device, "com.apple.pcapd")
75+
if err != nil {
76+
return NetworkInfo{}, fmt.Errorf("FindIPByLazy: failed connecting to com.apple.pcapd with err: %w", err)
77+
}
7478

75-
go func() {
76-
captureError <- startCapture(device, c, done)
77-
}()
79+
log.Infof("FindIPByLazy: connected to pcapd. waiting %v", capture_duration)
7880

79-
// captureDuration := time.Duration(10 * time.Second)
80-
startTime := time.Now()
8181
ipv6Hits := make(map[string]int)
8282
ipv4Hits := make(map[string]int)
83-
for packet := range c {
84-
if time.Now().Sub(startTime) > capture_duration {
85-
done <- true
86-
break
87-
}
83+
endSignal := time.After(capture_duration)
8884

89-
if packet.IPv4 != "" {
90-
ipv4Hits[packet.IPv4] += 1
91-
}
92-
if packet.IPv6 != "" {
93-
ipv6Hits[packet.IPv6] += 1
94-
}
95-
}
85+
L:
86+
for {
87+
select {
88+
case <-endSignal:
89+
break L
90+
default:
91+
packet, err := readPacket(pcapService.Reader())
92+
if err != nil {
93+
return NetworkInfo{}, fmt.Errorf("FindIPByLazy: error reading pcap packet: %w", err)
94+
}
95+
if packet.IPv4 != "" {
96+
ipv4Hits[packet.IPv4] += 1
97+
}
98+
if packet.IPv6 != "" {
99+
ipv6Hits[packet.IPv6] += 1
100+
}
96101

97-
captureErrorResult := <-captureError
98-
if captureErrorResult != nil {
99-
return NetworkInfo{}, fmt.Errorf("FindIPByLazy: failed to startCapture got err: %w", captureErrorResult)
102+
}
100103
}
101104

102105
highestIPv4Hits, highestIPv4Addr := 0, ""
@@ -118,44 +121,28 @@ func FindIPByLazy(device ios.DeviceEntry, capture_duration time.Duration) (Netwo
118121
return NetworkInfo{IPv4: highestIPv4Addr, IPv6: highestIPv6Addr}, nil
119122
}
120123

121-
func startCapture(device ios.DeviceEntry, c chan PacketInfo, done chan bool) error {
122-
intf, err := ios.ConnectToService(device, "com.apple.pcapd")
124+
var plistCodec = ios.NewPlistCodec()
125+
126+
func readPacket(r io.Reader) (PacketInfo, error) {
127+
b, err := plistCodec.Decode(r)
123128
if err != nil {
124-
return fmt.Errorf("startCapture: failed connecting to com.apple.pcapd with err: %w", err)
129+
return PacketInfo{}, fmt.Errorf("readPacket: failed decoding plistCodec err: %w", err)
125130
}
126-
127-
plistCodec := ios.NewPlistCodec()
128-
for {
129-
// if the channel is signalling to stop
130-
select {
131-
case <-done:
132-
return nil
133-
default:
134-
}
135-
136-
b, err := plistCodec.Decode(intf.Reader())
137-
if err != nil {
138-
return fmt.Errorf("startCapture: failed decoding plistCodec err: %w", err)
139-
}
140-
decodedBytes, err := fromBytes(b)
141-
if err != nil {
142-
return fmt.Errorf("startCapture: failed decoding fromBytes err: %w", err)
143-
}
144-
_, packet, err := getPacket(decodedBytes)
145-
if err != nil {
146-
return fmt.Errorf("startCapture: failed getPacket err: %w", err)
147-
}
148-
if len(packet) > 0 {
149-
pInfo := parsePacket(packet)
150-
if !pInfo.complete() {
151-
continue
152-
}
153-
154-
c <- pInfo
131+
decodedBytes, err := fromBytes(b)
132+
if err != nil {
133+
return PacketInfo{}, fmt.Errorf("readPacket: failed decoding fromBytes err: %w", err)
134+
}
135+
_, packet, err := getPacket(decodedBytes)
136+
if err != nil {
137+
return PacketInfo{}, fmt.Errorf("readPacket: failed getPacket err: %w", err)
138+
}
139+
if len(packet) > 0 {
140+
pInfo := parsePacket(packet)
141+
if pInfo.complete() {
142+
return pInfo, nil
155143
}
156144
}
157-
158-
return nil
145+
return PacketInfo{}, nil
159146
}
160147

161148
func parsePacket(p []byte) PacketInfo {

main.go

+15-10
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Usage:
9595
ios httpproxy remove [options]
9696
ios pair [--p12file=<orgid>] [--password=<p12password>] [options]
9797
ios ps [--apps] [options]
98-
ios ip [options] [--lazy] [--duration <sec>]
98+
ios ip [options] [--lazy] [--timeout=<sec>]
9999
ios forward [options] <hostPort> <targetPort>
100100
ios dproxy [--binary]
101101
ios readpair [options]
@@ -184,12 +184,13 @@ The commands work as following:
184184
> Use --nojson for a human-readable listing including BundleID when available. (not included with JSON output)
185185
> --apps limits output to processes flagged by iOS as "isApplication". This greatly-filtered list
186186
> should at least include user-installed software. Additional packages will also be displayed depending on the version of iOS.
187-
ios ip [options] [--lazy] [--duration <sec> Uses the live pcap iOS packet capture to wait until it finds one that contains the IP address of the device.
187+
ios ip [options] [--lazy] [--timeout=<sec>] Uses the live pcap iOS packet capture to wait until it finds one that contains the IP address of the device.
188188
> It relies on the MAC address of the WiFi adapter to know which is the right IP.
189-
> You have to disable the "automatic wifi address"-privacy feature of the device for this to work.
189+
> You have to disable the "automatic wifi address"-privacy feature of the device for this to work (if not possible, look at lazy option).
190190
> If you wanna speed it up, open apple maps or similar to force network traffic.
191-
> f.ex. "ios launch com.apple.Maps"
192-
> if using lazy, it will listen for a predefined time, and will return the IP with the most requests
191+
> f.ex. "ios launch com.apple.Maps".
192+
> If using lazy, it will listen for a predefined time, and will return the IP with the most requests, which does not require turning off randomized MAC.
193+
> It is a good idea to launch e.g. apple maps before starting lazy IP finding, as it creates a lot of unique traffic.
193194
ios forward [options] <hostPort> <targetPort> Similar to iproxy, forward a TCP connection to the device.
194195
ios dproxy [--binary] Starts the reverse engineering proxy server.
195196
> It dumps every communication in plain text so it can be implemented easily.
@@ -382,15 +383,19 @@ The commands work as following:
382383
var ip pcap.NetworkInfo
383384
var err error
384385

386+
// determine timeout for commands
387+
timeout, _ := arguments.Int("--timeout")
388+
if timeout == 0 {
389+
timeout = 10
390+
}
391+
385392
lazy, _ := arguments.Bool("--lazy")
386393
if !lazy {
387-
ip, err = pcap.FindIPByMac(device)
394+
ip, err = pcap.FindIPByMac(device, time.Second*time.Duration(timeout))
388395
} else {
389-
// duration, err := arguments.Int("--duration")
390-
duration := 10
391-
ip, err = pcap.FindIPByLazy(device, time.Duration(time.Duration(duration)*time.Second))
392-
396+
ip, err = pcap.FindIPByLazy(device, time.Second*time.Duration(timeout))
393397
}
398+
394399
exitIfError("failed", err)
395400
println(convertToJSONString(ip))
396401
return

0 commit comments

Comments
 (0)