Skip to content

Skip connections bind to local IPAddress - #389

Open
Zhidong Peng (ZhidongPeng) wants to merge 9 commits into
Azure:devfrom
ZhidongPeng:bindLocalIP
Open

Skip connections bind to local IPAddress#389
Zhidong Peng (ZhidongPeng) wants to merge 9 commits into
Azure:devfrom
ZhidongPeng:bindLocalIP

Conversation

@ZhidongPeng

@ZhidongPeng Zhidong Peng (ZhidongPeng) commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Context:
Client http request bind to local ip (ex 10.0.0.4) when communicating to the host endpoints, for example:

GPA ProxyServer listens to loopback/localhost IP, but OS networking kernel, not eBPF, could NOT redirect such requests to loopback/localhost IP address. The OS rejects this because:

  • Loopback is a closed loop: Traffic on 127.0.0.0/8 is expected to originate and terminate on the loopback interface. A packet with source 10.0.0.4 arriving on loopback violates this assumption.
  • Reverse path validation: The kernel (Linux rp_filter, Windows strong host model) checks that the source IP is reachable via the interface the packet arrives on. 10.0.0.4 is not reachable via loopback, so the packet is dropped.
  • Route selection: The kernel picks the outgoing interface based on the destination. For 127.0.0.1, it selects loopback. But the bound source IP doesn't belong to loopback, causing a "network unreachable" or silent drop.

Changes:

  • Add ebpf map config_map to accept settings GPA_CONFIG_LOCAL_IP_BIND_MONITOR_ONLY
  • Add ebpf map audit_only_map to cache connections bind to local IP address
  • if GPA_CONFIG_LOCAL_IP_BIND_MONITOR_ONLY set, skip the redirect if the connections bind to local IP Address
  • Start poll_audit_only task to read/pop the elem from ebpf map audit_only_map and emit telemetry event every few seconds.

Known issue:

  • As the poll_audit_only task to read/pop every few seconds, the process details may not available if the process exits quickly


#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct audit_only_event {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

it does not match gpa_audit_event.h

// Audit-only ring-buffer record. The kernel timestamp is monotonic; user mode
// adds UTC at receipt because eBPF does not expose a UTC clock on all platforms.
struct gpa_audit_only_event
{
    __u64 kernel_timestamp_ns;
    __u32 local_ipv4;
    struct gpa_audit_event audit;
};


pub struct AuditOnlyRecord {
pub entry: AuditEntry,
pub kernel_timestamp_ns: u64,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

we need to use this kernel_timestamp_ns to tell this pid is a valid one or not.

pub entry: AuditEntry,
pub kernel_timestamp_ns: u64,
pub timestamp_utc_ns: i128,
pub local_ipv4: u32,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

we may need to have ipv6?

.await
{
Ok(claims) => format!(
"eBPF audit-only connection: timestampUtcNs={}, kernelTimestampNs={}, localIp={}, userName={}, processId={}, processName={}, processFullPath={}, processCmdLine={}, runAsElevated={}, destination={}:{}",

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

message prefix is unnecessary.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

timestampUtcNs and kernelTimestampNs are not human readable

let destination_port = entry.destination_port_in_host_byte_order();
let message = match Claims::from_audit_entry(
&entry,
std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED), // not used for audit-only, so just use unspecified

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

please indicate why they are not used, are they included into the telemetry message?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

client_ip is needed,
local_port is not needed/used.

};
event_logger::write_event(
LoggerLevel::Warn,
message,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

how to query or filter the message? let's use json format for the message.

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.

1 participant