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

Don't check endieness on the host #139

Closed
anubhabMajumdar opened this issue Mar 26, 2024 · 8 comments · Fixed by #443
Closed

Don't check endieness on the host #139

anubhabMajumdar opened this issue Mar 26, 2024 · 8 comments · Fixed by #443
Assignees
Milestone

Comments

@anubhabMajumdar
Copy link
Contributor

Describe the bug
Currently Retina checks host endianness to enrich port/IP addresses. That is not correct, network is big-endian. Handle conversion in bpf code.

To Reproduce

Ref:

func determineEndian() binary.ByteOrder {

Expected behavior
Network is big-endian. Handle conversion as such bpf code.

Platform (please complete the following information):

  • OS: Linux
  • Kubernetes Version: N/A
  • Host: Linux/all-arch
  • Retina Version: v0.0.1
@anubhabMajumdar anubhabMajumdar added type/bug Something isn't working good first issue Good for newcomers help wanted Extra attention is needed area/plugins area/ebpf labels Mar 26, 2024
@anubhabMajumdar anubhabMajumdar added this to the v0.0.2 milestone Mar 26, 2024
@rbtr rbtr modified the milestones: v0.0.2, v0.0.3 Mar 26, 2024
@rbtr
Copy link
Collaborator

rbtr commented Mar 27, 2024

@hainenber can you comment here if you want this issue assigned to you also?

@hainenber
Copy link
Contributor

Yes, please :D

@rbtr rbtr assigned rbtr and hainenber and unassigned rbtr Mar 28, 2024
@rbtr rbtr added priority/2 P2 and removed good first issue Good for newcomers help wanted Extra attention is needed labels Mar 28, 2024
@anubhabMajumdar
Copy link
Contributor Author

What we want is to handle host to network conversion in bpf code and not handle it in userspace, making the code more efficient. Ideally, we won't need HostToNetwork and IntToIp won't need endianness check.

Some references for issue owner to consider:

@hainenber
Copy link
Contributor

Oh that wasn't what I expect at first 😆 . I was just thinking the conversion is already somewhere in eBPF codebase.

Thanks for the lead, I'll try getting my hands wet on this one as I didn't work on low-level code before :D

@rbtr rbtr modified the milestones: 2024/04/02, 2024/04/09 Apr 3, 2024
@rectified95
Copy link
Contributor

Hand-rolled byte order swap for IPv4 (32-bit addresses):

uint32_t s = 0x80010000;
s = (s & 0x0000FFFF) << 16 | (s & 0xFFFF0000) >> 16;
s = (s & 0x00FF00FF) << 8 | (s & 0xFF00FF00) >> 8; 
cout << setw(8) << setfill('0') << s << endl;

@rbtr rbtr assigned rectified95 and unassigned hainenber May 15, 2024
@rbtr
Copy link
Collaborator

rbtr commented May 15, 2024

Hand-rolled byte order swap for IPv4 (32-bit addresses):

uint32_t s = 0x80010000;
s = (s & 0x0000FFFF) << 16 | (s & 0xFFFF0000) >> 16;
s = (s & 0x00FF00FF) << 8 | (s & 0xFF00FF00) >> 8; 
cout << setw(8) << setfill('0') << s << endl;

@rectified95 maybe you can pick this up now? 🙂

@nddq
Copy link
Contributor

nddq commented May 31, 2024

just want to dust off this issue, when we are getting the src and dst ips from the iphdr
image
they might already are big-endian?
image
so we might not need to do conversation at all? correct me if im wrong 🙂 @anubhabMajumdar

@rectified95
Copy link
Contributor

@nddq Yes, those values are always big-endian and need to be converted to little-endian so they can be used by the hosts. I'm working on this now. The question is whether doing this simple operation in bpf is much faster than in Go, but it def wouldn't hurt.

rectified95 added a commit to rectified95/retina that referenced this issue Jun 5, 2024
github-merge-queue bot pushed a commit that referenced this issue Jun 7, 2024
# Description

Function `determineEndian()` always returns the same value since the
host byte order is always little-endian, so it can be skipped.
What's more, the byte order of IP address values passed by eBPF programs
doesn't need to be changed, because Golang's `net.IP` type expects
big-endian byte arrays.

**Details:**

We always enter this if-branch `binary.LittleEndian.PutUint32(ip, nn)`
which looks like it performs conversion TO little-endian, while it
actually expects to receive input already IN little-endian.
Note, the input number's bytes are kept in the same order - this
function merely converts a uint32 to a byte array. The result is we
convert a big-endian number to a big-endian byte array.

```
func (littleEndian) PutUint32(b []byte, v uint32) {
	_ = b[3] // early bounds check to guarantee safety of writes below
	b[0] = byte(v)
	b[1] = byte(v >> 8)
	b[2] = byte(v >> 16)
	b[3] = byte(v >> 24)
}
```
Crucially, `net.IP` expects big-endian byte arrays. For example, IP
`15.14.0.0` (`0x0F0E0000` in host order, and `0x00000E0F` in network
order) should be passed in as `[0F, 0E, 00, 00]` (most significant byte
at the lowest memory address) and so doesn't need inverting. Example
here: https://play.golang.com/p/ykiP6mLB_gG

In summary, we currently do not perform byte order conversion and
shouldn't start to, either in GO or eBPF code.
## Related Issue

Fixes #139 

This PR looks almost identical to
#161 which was rejected because
it didn't include byte order conversion in eBPF, but turns out that's
not needed. It also uses the correct uint-to-array conversion functions.

## Checklist

- [x] I have read the [contributing
documentation](https://retina.sh/docs/contributing).
- [x] I signed and signed-off the commits (`git commit -S -s ...`). See
[this
documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
on signing commits.
- [x] I have correctly attributed the author(s) of the code.
- [x] I have tested the changes locally.
- [x] I have followed the project's style guidelines.
- [x] I have updated the documentation, if necessary.
- [x] I have added tests, if applicable.

Signed-off-by: Igor Klemenski <[email protected]>
@nddq nddq closed this as completed in #443 Jun 7, 2024
Carpe-Wang pushed a commit to Carpe-Wang/retina that referenced this issue Jun 11, 2024
…microsoft#443)

Function `determineEndian()` always returns the same value since the
host byte order is always little-endian, so it can be skipped.
What's more, the byte order of IP address values passed by eBPF programs
doesn't need to be changed, because Golang's `net.IP` type expects
big-endian byte arrays.

**Details:**

We always enter this if-branch `binary.LittleEndian.PutUint32(ip, nn)`
which looks like it performs conversion TO little-endian, while it
actually expects to receive input already IN little-endian.
Note, the input number's bytes are kept in the same order - this
function merely converts a uint32 to a byte array. The result is we
convert a big-endian number to a big-endian byte array.

```
func (littleEndian) PutUint32(b []byte, v uint32) {
	_ = b[3] // early bounds check to guarantee safety of writes below
	b[0] = byte(v)
	b[1] = byte(v >> 8)
	b[2] = byte(v >> 16)
	b[3] = byte(v >> 24)
}
```
Crucially, `net.IP` expects big-endian byte arrays. For example, IP
`15.14.0.0` (`0x0F0E0000` in host order, and `0x00000E0F` in network
order) should be passed in as `[0F, 0E, 00, 00]` (most significant byte
at the lowest memory address) and so doesn't need inverting. Example
here: https://play.golang.com/p/ykiP6mLB_gG

In summary, we currently do not perform byte order conversion and
shouldn't start to, either in GO or eBPF code.

Fixes microsoft#139

This PR looks almost identical to
microsoft#161 which was rejected because
it didn't include byte order conversion in eBPF, but turns out that's
not needed. It also uses the correct uint-to-array conversion functions.

- [x] I have read the [contributing
documentation](https://retina.sh/docs/contributing).
- [x] I signed and signed-off the commits (`git commit -S -s ...`). See
[this
documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
on signing commits.
- [x] I have correctly attributed the author(s) of the code.
- [x] I have tested the changes locally.
- [x] I have followed the project's style guidelines.
- [x] I have updated the documentation, if necessary.
- [x] I have added tests, if applicable.

Signed-off-by: Igor Klemenski <[email protected]>
Signed-off-by: Carpe-Wang <[email protected]>
matmerr pushed a commit to matmerr/retina that referenced this issue Jul 3, 2024
…microsoft#443)

# Description

Function `determineEndian()` always returns the same value since the
host byte order is always little-endian, so it can be skipped.
What's more, the byte order of IP address values passed by eBPF programs
doesn't need to be changed, because Golang's `net.IP` type expects
big-endian byte arrays.

**Details:**

We always enter this if-branch `binary.LittleEndian.PutUint32(ip, nn)`
which looks like it performs conversion TO little-endian, while it
actually expects to receive input already IN little-endian.
Note, the input number's bytes are kept in the same order - this
function merely converts a uint32 to a byte array. The result is we
convert a big-endian number to a big-endian byte array.

```
func (littleEndian) PutUint32(b []byte, v uint32) {
	_ = b[3] // early bounds check to guarantee safety of writes below
	b[0] = byte(v)
	b[1] = byte(v >> 8)
	b[2] = byte(v >> 16)
	b[3] = byte(v >> 24)
}
```
Crucially, `net.IP` expects big-endian byte arrays. For example, IP
`15.14.0.0` (`0x0F0E0000` in host order, and `0x00000E0F` in network
order) should be passed in as `[0F, 0E, 00, 00]` (most significant byte
at the lowest memory address) and so doesn't need inverting. Example
here: https://play.golang.com/p/ykiP6mLB_gG

In summary, we currently do not perform byte order conversion and
shouldn't start to, either in GO or eBPF code.
## Related Issue

Fixes microsoft#139 

This PR looks almost identical to
microsoft#161 which was rejected because
it didn't include byte order conversion in eBPF, but turns out that's
not needed. It also uses the correct uint-to-array conversion functions.

## Checklist

- [x] I have read the [contributing
documentation](https://retina.sh/docs/contributing).
- [x] I signed and signed-off the commits (`git commit -S -s ...`). See
[this
documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
on signing commits.
- [x] I have correctly attributed the author(s) of the code.
- [x] I have tested the changes locally.
- [x] I have followed the project's style guidelines.
- [x] I have updated the documentation, if necessary.
- [x] I have added tests, if applicable.

Signed-off-by: Igor Klemenski <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment