Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5193,6 +5193,14 @@ declare module "bun" {
interface SocketAddress {
/**
* The IP address of the client.
*
* A link-local IPv6 address (`fe80::/10`) has its zone: the name of the
* interface, or the index of the interface on Windows. `Bun.connect()`,
* `Bun.udpSocket()`, `node:net` and `node:dgram` take the address with
* its zone. A URL cannot hold a zone, so `fetch()` and `WebSocket` do
* not.
*
* @example "192.168.1.100" | "2001:db8::1" | "fe80::1%eth0"
*/
address: string;

Expand Down Expand Up @@ -7310,7 +7318,10 @@ declare module "bun" {

/**
* Remote IP address connected to the socket
* @example "192.168.1.100" | "2001:db8::1"
*
* A link-local IPv6 address (`fe80::/10`) has its zone: the name of the
* interface, or the index of the interface on Windows.
* @example "192.168.1.100" | "2001:db8::1" | "fe80::1%eth0"
*/
readonly remoteAddress: string;

Expand All @@ -7328,7 +7339,10 @@ declare module "bun" {

/**
* Local IP address connected to the socket
* @example "192.168.1.100" | "2001:db8::1"
*
* A link-local IPv6 address (`fe80::/10`) has its zone: the name of the
* interface, or the index of the interface on Windows.
* @example "192.168.1.100" | "2001:db8::1" | "fe80::1%eth0"
*/
readonly localAddress: string;

Expand Down
4 changes: 4 additions & 0 deletions packages/bun-types/serve.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ declare module "bun" {
/**
* The IP address of the client.
*
* A link-local IPv6 address (`fe80::/10`) has its zone: the name of the
* interface, or the index of the interface on Windows. For example
* `"fe80::1%eth0"`.
*
* @example
* ```ts
* console.log(socket.remoteAddress); // "127.0.0.1"
Expand Down
10 changes: 10 additions & 0 deletions packages/bun-usockets/src/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,16 @@ int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
return 0;
}

int bsd_local_sockaddr(LIBUS_SOCKET_DESCRIPTOR fd, struct sockaddr_storage *out) {
socklen_t len = sizeof(*out);
return getsockname(fd, (struct sockaddr *) out, &len) == 0 && (out->ss_family == AF_INET || out->ss_family == AF_INET6);
}

int bsd_remote_sockaddr(LIBUS_SOCKET_DESCRIPTOR fd, struct sockaddr_storage *out) {
socklen_t len = sizeof(*out);
return getpeername(fd, (struct sockaddr *) out, &len) == 0 && (out->ss_family == AF_INET || out->ss_family == AF_INET6);
}

char *bsd_addr_get_ip(struct bsd_addr_t *addr) {
return addr->ip;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/bun-usockets/src/internal/networking/bsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ void internal_finalize_bsd_addr(struct bsd_addr_t *addr);
int bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr);
int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr);

/* getsockname() / getpeername() into `out`. Returns 1 for an AF_INET or AF_INET6 address, 0 otherwise. */
int bsd_local_sockaddr(LIBUS_SOCKET_DESCRIPTOR fd, struct sockaddr_storage *out);
int bsd_remote_sockaddr(LIBUS_SOCKET_DESCRIPTOR fd, struct sockaddr_storage *out);

char *bsd_addr_get_ip(struct bsd_addr_t *addr);
int bsd_addr_get_ip_length(struct bsd_addr_t *addr);

Expand Down
13 changes: 10 additions & 3 deletions packages/bun-usockets/src/libusockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ struct us_udp_packet_buffer_t;
struct ssl_ctx_st;
struct ssl_st;

/* <sys/socket.h> / <winsock2.h>. The address getters fill one whole: a link-local address needs its sin6_scope_id. */
struct sockaddr_storage;

/* Public interface for UDP sockets */

/* Peeks data and length of UDP payload */
Expand All @@ -199,6 +202,10 @@ int us_udp_packet_buffer_truncated(struct us_udp_packet_buffer_t *buf, int index
/* Get the bound port in host byte order */
int us_udp_socket_bound_port(struct us_udp_socket_t *s);

/* getsockname() / getpeername() into `out`. Returns 1 for an AF_INET or AF_INET6 address, 0 otherwise. */
int us_udp_socket_local_sockaddr(struct us_udp_socket_t *s, struct sockaddr_storage *out);
int us_udp_socket_remote_sockaddr(struct us_udp_socket_t *s, struct sockaddr_storage *out);

/* Peeks peer addr (sockaddr) of received packet */
char *us_udp_packet_buffer_peer(struct us_udp_packet_buffer_t *buf, int index);

Expand Down Expand Up @@ -725,8 +732,9 @@ struct us_socket_t *us_socket_close_lingering(us_socket_r s) nonnull_fn_decl;

int us_socket_local_port(us_socket_r s) nonnull_fn_decl;
int us_socket_remote_port(us_socket_r s) nonnull_fn_decl;
void us_socket_remote_address(us_socket_r s, char *nonnull_arg buf, int *nonnull_arg length) nonnull_fn_decl;
void us_socket_local_address(us_socket_r s, char *nonnull_arg buf, int *nonnull_arg length) nonnull_fn_decl;
/* getsockname() / getpeername() into `out`. Returns 0 for a unix socket, a named pipe and a closed socket. */
int us_socket_local_sockaddr(us_socket_r s, struct sockaddr_storage *nonnull_arg out) nonnull_fn_decl;
int us_socket_remote_sockaddr(us_socket_r s, struct sockaddr_storage *nonnull_arg out) nonnull_fn_decl;

int us_socket_ipc_write_fd(us_socket_r s, const char *data, int length, int fd) nonnull_fn_decl;
/* Dispatches on_writable once the socket is writable, as if a us_socket_write() had come up short.
Expand All @@ -748,7 +756,6 @@ struct us_socket_t *us_socket_from_fd(us_socket_group_r group, unsigned char kin
__attribute__((nonnull(1))); /* ssl_ctx nullable */
/* The bundled Mozilla root certificates, DER-encoded, in static memory. Returns the count. */
size_t us_bundled_root_certs_der(const uint8_t *const **out_certs, const size_t **out_lens);
unsigned int us_get_remote_address_info(char *buf, us_socket_r s, int *port);
int us_socket_get_error(us_socket_r s);
/* A writable event's write made zero progress: does that prove the peer is
* gone? On epoll/kqueue a writable event implies real send-buffer space, so
Expand Down
36 changes: 17 additions & 19 deletions packages/bun-usockets/src/quic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1274,15 +1274,9 @@ int us_quic_listen_socket_port(us_quic_udp_t *ls) {
: ((struct sockaddr_in *) &ls->local)->sin_port);
}

int us_quic_listen_socket_local_address(us_quic_udp_t *ls, char *buf, int len) {
if (ls->local.ss_family == AF_INET6) {
if (len < 16) return 0;
memcpy(buf, &((struct sockaddr_in6 *) &ls->local)->sin6_addr, 16);
return 16;
}
if (len < 4) return 0;
memcpy(buf, &((struct sockaddr_in *) &ls->local)->sin_addr, 4);
return 4;
int us_quic_listen_socket_local_sockaddr(us_quic_udp_t *ls, struct sockaddr_storage *out) {
*out = ls->local;
return out->ss_family == AF_INET || out->ss_family == AF_INET6;
}

#define DEF_CB(name, sig) \
Expand Down Expand Up @@ -1469,23 +1463,27 @@ int us_quic_stream_headers_too_large(us_quic_stream_t *s) {

void *us_quic_socket_ext(us_quic_socket_t *s) { return s + 1; }

void us_quic_socket_remote_address(us_quic_socket_t *s, char *buf, int *len, int *port, int *is_ipv6) {
int us_quic_socket_remote_sockaddr(us_quic_socket_t *s, struct sockaddr_storage *out) {
const struct sockaddr *local, *peer;
*len = 0; *port = 0; *is_ipv6 = 0;
if (lsquic_conn_get_sockaddr(s->conn, &local, &peer) != 0) return;
if (lsquic_conn_get_sockaddr(s->conn, &local, &peer) != 0) return 0;
if (peer->sa_family == AF_INET6) {
const struct sockaddr_in6 *a = (const struct sockaddr_in6 *) peer;
*port = ntohs(a->sin6_port);
if (IN6_IS_ADDR_V4MAPPED(&a->sin6_addr)) {
*len = 4; memcpy(buf, (const char *) &a->sin6_addr + 12, 4);
/* An IPv4 peer of a dual-stack socket: ::ffff:a.b.c.d is reported as a.b.c.d. */
struct sockaddr_in v4;
memset(&v4, 0, sizeof(v4));
v4.sin_family = AF_INET;
v4.sin_port = a->sin6_port;
memcpy(&v4.sin_addr, (const char *) &a->sin6_addr + 12, 4);
memcpy(out, &v4, sizeof(v4));
} else {
*is_ipv6 = 1; *len = 16; memcpy(buf, &a->sin6_addr, 16);
memcpy(out, a, sizeof(*a));
}
} else {
const struct sockaddr_in *a = (const struct sockaddr_in *) peer;
*port = ntohs(a->sin_port);
*len = 4; memcpy(buf, &a->sin_addr, 4);
return 1;
}
if (peer->sa_family != AF_INET) return 0;
memcpy(out, peer, sizeof(struct sockaddr_in));
return 1;
}

void us_quic_socket_close(us_quic_socket_t *s) { if (s->conn) lsquic_conn_close(s->conn); }
Expand Down
6 changes: 4 additions & 2 deletions packages/bun-usockets/src/quic.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ us_quic_udp_t *us_quic_socket_context_listen(

void us_quic_listen_socket_close(us_quic_udp_t *ls);
int us_quic_listen_socket_port(us_quic_udp_t *ls);
int us_quic_listen_socket_local_address(us_quic_udp_t *ls, char *buf, int len);
/* The address that the listener is bound to, whole. Returns 1 for an AF_INET or AF_INET6 address, 0 otherwise. */
int us_quic_listen_socket_local_sockaddr(us_quic_udp_t *ls, struct sockaddr_storage *out);

/* Client engine: one shared lsquic engine for all outbound connections on
* `loop`. Per-connection cert verification is decided at connect time. */
Expand Down Expand Up @@ -247,7 +248,8 @@ int us_quic_stream_headers_too_large(us_quic_stream_t *s);

/* Connection accessors */
void *us_quic_socket_ext(us_quic_socket_t *s);
void us_quic_socket_remote_address(us_quic_socket_t *s, char *buf, int *len, int *port, int *is_ipv6);
/* The peer of the connection, whole. An IPv4 peer of a dual-stack socket is AF_INET. Returns 1, or 0 with no peer. */
int us_quic_socket_remote_sockaddr(us_quic_socket_t *s, struct sockaddr_storage *out);
void us_quic_socket_close(us_quic_socket_t *s);

#ifdef __cplusplus
Expand Down
45 changes: 7 additions & 38 deletions packages/bun-usockets/src/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,15 @@ void us_connecting_socket_shutdown_read(struct us_connecting_socket_t *c) {
c->shutdown_read = 1;
}

void us_socket_remote_address(struct us_socket_t *s, char *buf, int *length) {
struct bsd_addr_t addr;
if (bsd_remote_addr(us_poll_fd(&s->p), &addr) || *length < bsd_addr_get_ip_length(&addr)) {
*length = 0;
} else {
*length = bsd_addr_get_ip_length(&addr);
memcpy(buf, bsd_addr_get_ip(&addr), *length);
}
/* 0 for a closed socket: the kernel can give its descriptor number to another connection. */
int us_socket_local_sockaddr(struct us_socket_t *s, struct sockaddr_storage *out) {
if (us_socket_is_closed(s)) return 0;
return bsd_local_sockaddr(us_poll_fd(&s->p), out);
}

void us_socket_local_address(struct us_socket_t *s, char *buf, int *length) {
struct bsd_addr_t addr;
if (bsd_local_addr(us_poll_fd(&s->p), &addr) || *length < bsd_addr_get_ip_length(&addr)) {
*length = 0;
} else {
*length = bsd_addr_get_ip_length(&addr);
memcpy(buf, bsd_addr_get_ip(&addr), *length);
}
int us_socket_remote_sockaddr(struct us_socket_t *s, struct sockaddr_storage *out) {
if (us_socket_is_closed(s)) return 0;
return bsd_remote_sockaddr(us_poll_fd(&s->p), out);
}

__attribute__((always_inline)) struct us_socket_group_t *us_socket_group(struct us_socket_t *s) {
Expand Down Expand Up @@ -802,28 +793,6 @@ int us_connecting_socket_get_dns_error(struct us_connecting_socket_t *c) {
return c->error_is_dns ? c->error : 0;
}

unsigned int us_get_remote_address_info(char *buf, struct us_socket_t *s, int *port)
{
// This function is manual inlining + modification of
// us_socket_remote_address
// AsyncSocket::getRemoteAddress
// To get { ip, port, is_ipv6 } for Bun.serve().requestIP()
struct bsd_addr_t addr;
if (bsd_remote_addr(us_poll_fd(&s->p), &addr)) {
return 0;
}

int length = bsd_addr_get_ip_length(&addr);
if (!length) {
return 0;
}

memcpy(buf, bsd_addr_get_ip(&addr), length);
*port = bsd_addr_get_port(&addr);

return length;
}

void us_socket_ref(struct us_socket_t *s) {
#ifdef LIBUS_USE_LIBUV
uv_ref((uv_handle_t *) s->p.uv_p);
Expand Down
20 changes: 4 additions & 16 deletions packages/bun-usockets/src/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,24 +84,12 @@ int us_udp_socket_bound_port(struct us_udp_socket_t *s) {
return s->port;
}

void us_udp_socket_bound_ip(struct us_udp_socket_t *s, char *buf, int *length) {
struct bsd_addr_t addr;
if (bsd_local_addr(us_poll_fd((struct us_poll_t *)s), &addr) || *length < bsd_addr_get_ip_length(&addr)) {
*length = 0;
} else {
*length = bsd_addr_get_ip_length(&addr);
memcpy(buf, bsd_addr_get_ip(&addr), *length);
}
int us_udp_socket_local_sockaddr(struct us_udp_socket_t *s, struct sockaddr_storage *out) {
return bsd_local_sockaddr(us_poll_fd((struct us_poll_t *) s), out);
}

void us_udp_socket_remote_ip(struct us_udp_socket_t *s, char *buf, int *length) {
struct bsd_addr_t addr;
if (bsd_remote_addr(us_poll_fd((struct us_poll_t *)s), &addr) || *length < bsd_addr_get_ip_length(&addr)) {
*length = 0;
} else {
*length = bsd_addr_get_ip_length(&addr);
memcpy(buf, bsd_addr_get_ip(&addr), *length);
}
int us_udp_socket_remote_sockaddr(struct us_udp_socket_t *s, struct sockaddr_storage *out) {
return bsd_remote_sockaddr(us_poll_fd((struct us_poll_t *) s), out);
}

__attribute__((always_inline)) void *us_udp_socket_user(struct us_udp_socket_t *udp) {
Expand Down
8 changes: 0 additions & 8 deletions packages/bun-uws/src/AsyncSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,6 @@ struct AsyncSocket {
return true;
}

/* Returns the remote IP address or empty string on failure */
std::string_view getRemoteAddress() {
static thread_local char buf[16];
int ipLength = 16;
us_socket_remote_address((us_socket_t *) this, buf, &ipLength);
return std::string_view(buf, (unsigned int) ipLength);
}

/**
* Flushes the socket buffer by writing as much data as possible to the underlying socket.
*
Expand Down
1 change: 0 additions & 1 deletion packages/bun-uws/src/HttpResponse.h
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,6 @@ struct HttpResponse : public AsyncSocket<SSL> {
using Super::close;

/* See AsyncSocket */
using Super::getRemoteAddress;
using Super::getNativeHandle;

/* Stops reading for a READ_PAUSE_* reason. The idle timeout keeps running, because a blocked response write has nothing else to end it. */
Expand Down
1 change: 0 additions & 1 deletion packages/bun-uws/src/WebSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ struct WebSocket : AsyncSocket<SSL> {

/* See AsyncSocket */
using Super::getBufferedAmount;
using Super::getRemoteAddress;
using Super::getNativeHandle;

/* WebSocket close cannot be an alias to AsyncSocket::close since
Expand Down
Loading
Loading