Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Find IP based on packets without MAC #302

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

eyJhb
Copy link
Contributor

@eyJhb eyJhb commented Nov 10, 2023

This implements a way to find the IP address of the device, without using the mac address of the device.
Basically just counts the number of occurrences of the IP in the src, and then takes the one with the most, as it's most likely to be the correct one.

Works fine, if you make some noise while it's running.

I can't get the --duration to work however, not sure why.

But I would appreciate some comments on this.

Also functions are not named findIp, findIp and findIP anymore. Should be more readable.

@shamanec and @danielpaulus WIP as I would appreciate any comments on this.

@danielpaulus
Copy link
Owner

danielpaulus commented Dec 20, 2023

@eyJhb haha that's a clever hack! I like it :-D
Probabilistic IP analysis. I'll take a look now.

wdyt about adding a flag that automatically creates noise?
I found that opening Safari, or the weather app usually causes network traffic. Maybe you can find other things too. We could offer this as part of this implementation.

}

func findIp(device ios.DeviceEntry, mac string) (NetworkInfo, error) {
intf, err := ios.ConnectToService(device, "com.apple.pcapd")
// FindIp reads pcap packets until one is found that matches the given MAC
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a comment explaining how this works

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be resolved in latest commit.

func startCapture(device ios.DeviceEntry, c chan PacketInfo, done chan bool) error {
intf, err := ios.ConnectToService(device, "com.apple.pcapd")
if err != nil {
return err
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recently learned that for debugging things later, in Golang it is a good practice to wrap errors and indicate the function name of where they happened. So rather than just returning err here and in other places, it is better to do sth like:
return fmt.Errorf("startCapture: failed connecting to com.apple.pcapd with err: %w, err)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be resolved in latest commit.

@eyJhb
Copy link
Contributor Author

eyJhb commented Dec 21, 2023

@eyJhb haha that's a clever hack! I like it :-D Probabilistic IP analysis. I'll take a look now.

wdyt about adding a flag that automatically creates noise? I found that opening Safari, or the weather app usually causes network traffic. Maybe you can find other things too. We could offer this as part of this implementation.

Thanks! I quite like it as well! :D - We could just open Apple Maps :) That generates a lot of traffic, and was something I was playing with. It could be a flag to disable/enable it.

I'll be looking at the PR again after Christmas, hopefully that's OK with you!

@danielpaulus
Copy link
Owner

@eyJhb haha that's a clever hack! I like it :-D Probabilistic IP analysis. I'll take a look now.
wdyt about adding a flag that automatically creates noise? I found that opening Safari, or the weather app usually causes network traffic. Maybe you can find other things too. We could offer this as part of this implementation.

Thanks! I quite like it as well! :D - We could just open Apple Maps :) That generates a lot of traffic, and was something I was playing with. It could be a flag to disable/enable it.

I'll be looking at the PR again after Christmas, hopefully that's OK with you!

That's a really good idea :-D
Yeah of course, whenever you have the time. I am grateful for every contribution. Enjoy your Christmas vacation then 👍

@eyJhb
Copy link
Contributor Author

eyJhb commented Jan 3, 2024

So I've fixed the two comments, but I haven't added another flag. I've thought if it wouldn't make more sense, to just tell the user to run something like ios launch <name-of-apple-maps-that-i-cant-remember> && ios ip --lazy, instead. This reduces the complexity of the implementation a lot :) What are your thoughts on this?

Also, I still have no clue why duration doesn't want to work from the arguments. Can you aid in that @danielpaulus ?

@danielpaulus
Copy link
Owner

I'll take a look later today. I love this PR, it wins my prize of most creative solution ever :-D

@danielpaulus
Copy link
Owner

danielpaulus commented Jan 3, 2024

I changed it to this to remove the goroutines

// FindIPByLazy reads pcap packets for a specified duration, whereafter it will
// try to find the IP address that occurs the most times, and assume that is the IP of the device.
// This is of course based on, that the device contacts mulitple IPs, and that there is some traffic.
// If the device only contains a single IP, then it would be 50/50 which IP will be returned.
// This is best effort! It's important to generate some traffic, when this function runs to get better results.
func FindIPByLazy(device ios.DeviceEntry, capture_duration time.Duration) (NetworkInfo, error) {
	pcapService, err := ios.ConnectToService(device, "com.apple.pcapd")
	if err != nil {
		return NetworkInfo{}, fmt.Errorf("FindIPByLazy: failed connecting to com.apple.pcapd with err: %w", err)
	}

	ipv6Hits := make(map[string]int)
	ipv4Hits := make(map[string]int)
	log.Infof("connected to pcapd. waiting %v", capture_duration)
	endSignal := time.After(capture_duration)
L:
	for {
		select {
		case <-endSignal:
			break L
		default:
			packet, err := readPacket(pcapService.Reader())
			if err != nil {
				return NetworkInfo{}, fmt.Errorf("FindIPByLazy: error reading pcap packet: %w", err)
			}
			if packet.IPv4 != "" {
				ipv4Hits[packet.IPv4] += 1
			}
			if packet.IPv6 != "" {
				ipv6Hits[packet.IPv6] += 1
			}

		}
	}

	highestIPv4Hits, highestIPv4Addr := 0, ""
	for ipv4, hits := range ipv4Hits {
		if hits > highestIPv4Hits {
			highestIPv4Hits = hits
			highestIPv4Addr = ipv4
		}
	}

	highestIPv6Hits, highestIPv6Addr := 0, ""
	for ipv6, hits := range ipv6Hits {
		if hits > highestIPv6Hits {
			highestIPv6Hits = hits
			highestIPv6Addr = ipv6
		}
	}

	return NetworkInfo{IPv4: highestIPv4Addr, IPv6: highestIPv6Addr}, nil
}

var plistCodec = ios.NewPlistCodec()

func readPacket(r io.Reader) (PacketInfo, error) {
	b, err := plistCodec.Decode(r)
	if err != nil {
		return PacketInfo{}, fmt.Errorf("readPacket: failed decoding plistCodec err: %w", err)
	}
	decodedBytes, err := fromBytes(b)
	if err != nil {
		return PacketInfo{}, fmt.Errorf("readPacket: failed decoding fromBytes err: %w", err)
	}
	_, packet, err := getPacket(decodedBytes)
	if err != nil {
		return PacketInfo{}, fmt.Errorf("readPacket: failed getPacket err: %w", err)
	}
	if len(packet) > 0 {
		pInfo := parsePacket(packet)
		if pInfo.complete() {
			return pInfo, nil
		}
	}
	return PacketInfo{}, nil
}

Wdyt?

@danielpaulus
Copy link
Owner

main.go I did like this:

ios ip [options] [--lazy=<duration_seconds>]

and then:

	b, _ = arguments.Bool("ip")
	if b {
		var ip pcap.NetworkInfo
		var err error

		lazy, _ := arguments.String("--lazy")
		if lazy == "" {
			ip, err = pcap.FindIPByMac(device)
		} else {
			seconds, err := arguments.Int("--lazy")
			if seconds <= 0 {
				log.Fatal("Please provide a positive, non zero integer for the duration.")
			}
			if err != nil {
				exitIfError("please provide an integer for the duration. like 'ios ip --lazy=5' for 5 seconds", err)
			}
			ip, err = pcap.FindIPByLazy(device, time.Duration(seconds)*time.Second)
			exitIfError("failed finding lazy IP", err)

		}
		exitIfError("failed", err)
		println(convertToJSONString(ip))
		return
	}

@eyJhb
Copy link
Contributor Author

eyJhb commented Jan 4, 2024

I'll take a look later today. I love this PR, it wins my prize of most creative solution ever :-D

Thanks! It's a neat little hack, when Apple doesn't want to expose such information (weirdos) :D

I changed it to this to remove the goroutines
...
Wdyt?

Much cleaner! Would much rather have that, than the goroutines! I'll be updating the PR to reflect that change. :)

main.go I did like this:

...

and then:

...

Perfect, thank you. I'll be playing around with that! :)
Hopefully I can get --lazy to behave without any duration added, and default to 30s.

Hopefully I'll be able to have it all put together, and tested before the end of the day.

@eyJhb
Copy link
Contributor Author

eyJhb commented Jan 29, 2024

So I've updated the PR with the latest changes. I really like the idea of using the timer for stopping the process, great work!
I've added a timeout for finding IP by mac as well, as it made sense to have in both. The syntax is now

go-ios ip --lazy --timeout=30
go-ios ip --timeout=30

It defaults to 10s timeout., which should be fine?

Sorry for not doing this before, it's been quite a busy time....

The lazy option will find the IP based on how many packets it sees
with X address. The IP with the most packets to/from should most
likely be the address of the device itself, unless it only contacts a
single other host.
@eyJhb
Copy link
Contributor Author

eyJhb commented Jan 29, 2024

I've squashed my commits into a single one, I think this is good to merge? Please test as well to ensure it however.

@danielpaulus
Copy link
Owner

sorry for the delay @eyJhb we've been a bit busy with the ios17 work. I will check and merge this today. Thank you so much for this clever solution :-D

@eyJhb
Copy link
Contributor Author

eyJhb commented Feb 22, 2024

sorry for the delay @eyJhb we've been a bit busy with the ios17 work. I will check and merge this today. Thank you so much for this clever solution :-D

Awesome! Take your time, I think that ios17 work is much more important :) So no pressure from me. If there is anything I can help you with to speed up the process, please do let me know! :)

@eyJhb
Copy link
Contributor Author

eyJhb commented Mar 13, 2024

@danielpaulus any time for reviewing this? :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants