Skip to content

Commit

Permalink
Add get_addr_dest_{ip,port} hostcalls
Browse files Browse the repository at this point in the history
  • Loading branch information
ulyssa committed Jul 3, 2024
1 parent 5647b08 commit 6a1d87a
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 16 deletions.
24 changes: 24 additions & 0 deletions crates/adapter/src/fastly/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,30 @@ pub mod fastly_http_resp {
pub fn close(resp_handle: ResponseHandle) -> FastlyStatus {
convert_result(fastly::api::http_resp::close(resp_handle))
}

#[export_name = "fastly_http_resp#get_addr_dest_ip"]
pub fn get_addr_dest_ip(
resp_handle: ResponseHandle,
addr_octets_out: *mut u8,
nwritten_out: *mut usize,
) -> FastlyStatus {
alloc_result!(addr_octets_out, 16, nwritten_out, {
fastly::api::http_resp::get_addr_dest_ip(resp_handle)
})
}

#[export_name = "fastly_http_resp#get_addr_dest_port"]
pub fn get_addr_dest_port(resp_handle: ResponseHandle, port_out: *mut u16) -> FastlyStatus {
match fastly::api::http_resp::get_addr_dest_port(resp_handle) {
Ok(port) => {
unsafe {
*port_out = port;
}
FastlyStatus::OK
}
Err(e) => e.into(),
}
}
}

pub mod fastly_dictionary {
Expand Down
18 changes: 18 additions & 0 deletions lib/compute-at-edge-abi/compute-at-edge.witx
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,24 @@
(param $mode $http_keepalive_mode)
(result $err (expected (error $fastly_status)))
)

;;; Hostcall for getting the destination IP used for this request.
;;;
;;; The buffer for the IP address must be 16 bytes. This will return
;;; the number of bytes written to the buffer: 4 for IPv4 addresses,
;;; and 16 for IPv6.
(@interface func (export "get_addr_dest_ip")
(param $h $response_handle)
;; must be a 16-byte array
(param $addr_octets_out (@witx pointer (@witx char8)))
(result $err (expected $num_bytes (error $fastly_status)))
)

;;; Hostcall for getting the destination port used for this request.
(@interface func (export "get_addr_dest_port")
(param $h $response_handle)
(result $err (expected $port (error $fastly_status)))
)
)

(module $fastly_dictionary
Expand Down
40 changes: 39 additions & 1 deletion lib/src/component/http_resp.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use {
super::fastly::api::{http_resp, http_types, types},
super::{headers::write_values, types::TrappableError},
crate::{error::Error, session::Session},
crate::{error::Error, session::Session, upstream},
cfg_if::cfg_if,
http::{HeaderName, HeaderValue},
hyper::http::response::Response,
std::net::IpAddr,
};

const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;
Expand Down Expand Up @@ -286,4 +287,41 @@ impl http_resp::Host for Session {
http_resp::KeepaliveMode::Automatic => Ok(()),
}
}

async fn get_addr_dest_ip(
&mut self,
resp_handle: http_types::ResponseHandle,
) -> Result<Vec<u8>, types::Error> {
let resp = self.response_parts(resp_handle.into())?;
let md = resp
.extensions
.get::<upstream::ConnMetadata>()
.ok_or(Error::ValueAbsent)?;

match md.remote_addr.ip() {
IpAddr::V4(addr) => {
let octets = addr.octets();
debug_assert_eq!(octets.len(), 4);
Ok(Vec::from(octets))
}
IpAddr::V6(addr) => {
let octets = addr.octets();
debug_assert_eq!(octets.len(), 16);
Ok(Vec::from(octets))
}
}
}

async fn get_addr_dest_port(
&mut self,
resp_handle: http_types::ResponseHandle,
) -> Result<u16, types::Error> {
let resp = self.response_parts(resp_handle.into())?;
let md = resp
.extensions
.get::<upstream::ConnMetadata>()
.ok_or(Error::ValueAbsent)?;
let port = md.remote_addr.port();
Ok(port)
}
}
50 changes: 35 additions & 15 deletions lib/src/upstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use hyper::{client::HttpConnector, header, Client, HeaderMap, Request, Response,
use rustls::client::ServerName;
use std::{
io,
net::SocketAddr,
pin::Pin,
str::FromStr,
sync::Arc,
Expand Down Expand Up @@ -96,8 +97,22 @@ impl BackendConnector {
type BoxError = Box<dyn std::error::Error + Send + Sync>;

pub enum Connection {
Http(TcpStream),
Https(Box<TlsStream<TcpStream>>),
Http(TcpStream, ConnMetadata),
Https(Box<TlsStream<TcpStream>>, ConnMetadata),
}

impl Connection {
fn metadata(&self) -> ConnMetadata {
match self {
Connection::Http(_, md) => md.clone(),
Connection::Https(_, md) => md.clone(),
}
}
}

#[derive(Clone)]
pub struct ConnMetadata {
pub remote_addr: SocketAddr,
}

impl hyper::service::Service<Uri> for BackendConnector {
Expand Down Expand Up @@ -138,7 +153,10 @@ impl hyper::service::Service<Uri> for BackendConnector {
Box::pin(async move {
let tcp = connect_fut.await.map_err(Box::new)?;

if backend.uri.scheme_str() == Some("https") {
let remote_addr = tcp.peer_addr()?;
let metadata = ConnMetadata { remote_addr };

let conn = if backend.uri.scheme_str() == Some("https") {
let mut config = if let Some(certed_key) = &backend.client_cert {
config.with_client_auth_cert(certed_key.certs(), certed_key.key())?
} else {
Expand Down Expand Up @@ -181,10 +199,12 @@ impl hyper::service::Service<Uri> for BackendConnector {
}
}

Ok(Connection::Https(Box::new(tls)))
Connection::Https(Box::new(tls), metadata)
} else {
Ok(Connection::Http(tcp))
}
Connection::Http(tcp, metadata)
};

Ok(conn)
})
}
}
Expand Down Expand Up @@ -346,7 +366,7 @@ pub struct SelectTarget {

impl hyper::client::connect::Connection for Connection {
fn connected(&self) -> hyper::client::connect::Connected {
hyper::client::connect::Connected::new()
hyper::client::connect::Connected::new().extra(self.metadata())
}
}

Expand All @@ -357,8 +377,8 @@ impl AsyncRead for Connection {
buf: &mut ReadBuf<'_>,
) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self) {
Connection::Http(s) => Pin::new(s).poll_read(cx, buf),
Connection::Https(s) => Pin::new(s).poll_read(cx, buf),
Connection::Http(s, _) => Pin::new(s).poll_read(cx, buf),
Connection::Https(s, _) => Pin::new(s).poll_read(cx, buf),
}
}
}
Expand All @@ -370,22 +390,22 @@ impl AsyncWrite for Connection {
buf: &[u8],
) -> Poll<Result<usize, io::Error>> {
match Pin::get_mut(self) {
Connection::Http(s) => Pin::new(s).poll_write(cx, buf),
Connection::Https(s) => Pin::new(s).poll_write(cx, buf),
Connection::Http(s, _) => Pin::new(s).poll_write(cx, buf),
Connection::Https(s, _) => Pin::new(s).poll_write(cx, buf),
}
}

fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self) {
Connection::Http(s) => Pin::new(s).poll_flush(cx),
Connection::Https(s) => Pin::new(s).poll_flush(cx),
Connection::Http(s, _) => Pin::new(s).poll_flush(cx),
Connection::Https(s, _) => Pin::new(s).poll_flush(cx),
}
}

fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self) {
Connection::Http(s) => Pin::new(s).poll_shutdown(cx),
Connection::Https(s) => Pin::new(s).poll_shutdown(cx),
Connection::Http(s, _) => Pin::new(s).poll_shutdown(cx),
Connection::Https(s, _) => Pin::new(s).poll_shutdown(cx),
}
}
}
46 changes: 46 additions & 0 deletions lib/src/wiggle_abi/resp_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use {
crate::{
error::Error,
session::Session,
upstream,
wiggle_abi::{
fastly_http_resp::FastlyHttpResp,
headers::HttpHeaders,
Expand All @@ -15,6 +16,7 @@ use {
},
cfg_if::cfg_if,
hyper::http::response::Response,
std::net::IpAddr,
wiggle::{GuestMemory, GuestPtr},
};

Expand Down Expand Up @@ -225,4 +227,48 @@ impl FastlyHttpResp for Session {
HttpKeepaliveMode::Automatic => Ok(()),
}
}

fn get_addr_dest_ip(
&mut self,
memory: &mut GuestMemory<'_>,
resp_handle: ResponseHandle,
addr_octets_ptr: GuestPtr<u8>,
) -> Result<u32, Error> {
let resp = self.response_parts(resp_handle)?;
let md = resp
.extensions
.get::<upstream::ConnMetadata>()
.ok_or(Error::ValueAbsent)?;

match md.remote_addr.ip() {
IpAddr::V4(addr) => {
let octets = addr.octets();
let octets_bytes = octets.len() as u32;
debug_assert_eq!(octets_bytes, 4);
memory.copy_from_slice(&octets, addr_octets_ptr.as_array(octets_bytes))?;
Ok(octets_bytes)
}
IpAddr::V6(addr) => {
let octets = addr.octets();
let octets_bytes = octets.len() as u32;
debug_assert_eq!(octets_bytes, 16);
memory.copy_from_slice(&octets, addr_octets_ptr.as_array(octets_bytes))?;
Ok(octets_bytes)
}
}
}

fn get_addr_dest_port(
&mut self,
_memory: &mut GuestMemory<'_>,
resp_handle: ResponseHandle,
) -> Result<u16, Error> {
let resp = self.response_parts(resp_handle)?;
let md = resp
.extensions
.get::<upstream::ConnMetadata>()
.ok_or(Error::ValueAbsent)?;
let port = md.remote_addr.port();
Ok(port)
}
}
4 changes: 4 additions & 0 deletions lib/wit/deps/fastly/compute.wit
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,10 @@ interface http-resp {

http-keepalive-mode-set: func(h: response-handle, mode: keepalive-mode) ->
result<_, error>;

get-addr-dest-ip: func(h: response-handle) -> result<list<u8>, error>;

get-addr-dest-port: func(h: response-handle) -> result<u16, error>;
}

/*
Expand Down

0 comments on commit 6a1d87a

Please sign in to comment.