Builtin slirp: several fixes and additions.

The slirplog object must exist before calling slirp_new().
Function slirplog_error() can handle arguments now.
Most of the fprintf() calls replaced by slirplog_error().
Added IPv6 host forwarding feature (not yet used by Bochs).
Added stubs for slirp_connection_info() and slirp_neighbor_info().
Fixed some warnings.
This commit is contained in:
Volker Ruppert 2024-05-18 23:14:45 +02:00
parent c5435aef15
commit b76ead90ed
16 changed files with 164 additions and 42 deletions

View File

@ -325,10 +325,10 @@ bx_slirp_pktmover_c::bx_slirp_pktmover_c(const char *netif,
config.vnameserver6.s6_addr[15] |= 3;
}
}
slirp = slirp_new(&config, &callbacks, this);
slirplog = new logfunctions();
sprintf(prefix, "SLIRP%d", bx_slirp_instances);
slirplog->put(prefix);
slirp = slirp_new(&config, &callbacks, this);
#if !BX_HAVE_LIBSLIRP
if (debug_switches != 0) {
slirplog->setonoff(LOGLEV_DEBUG, ACT_REPORT);

View File

@ -115,14 +115,13 @@ static void domain_fixup_order(CompactDomain *cd, size_t n)
}
}
static void domain_mklabels(Slirp *s, CompactDomain *cd, const char *input)
static void domain_mklabels(CompactDomain *cd, const char *input)
{
uint8_t *len_marker = cd->labels;
uint8_t *output = len_marker; /* pre-incremented */
const char *in = input;
char cur_chr;
size_t len = 0;
char msg[80];
if (cd->len == 0) {
goto fail;
@ -154,8 +153,7 @@ static void domain_mklabels(Slirp *s, CompactDomain *cd, const char *input)
return;
fail:
sprintf(msg, "failed to parse domain name '%s'\n", input);
slirplog_error(msg);
slirplog_error("failed to parse domain name '%s'", input);
cd->len = 0;
}
@ -271,7 +269,7 @@ int translate_dnssearch(Slirp *s, const char **names)
outptr = result;
for (i = 0; i < num_domains; i++) {
domains[i].labels = outptr;
domain_mklabels(s, domains + i, names[i]);
domain_mklabels(domains + i, names[i]);
if (domains[i].len == 0) {
/* Bogus entry, reject it all */
free(domains);

View File

@ -109,7 +109,7 @@ void icmp6_forward_error(struct mbuf *m, uint8_t type, uint8_t code, struct in6_
/* TODO: Handle this case */
break;
default:
fprintf(stderr, "Unknown ICMP code\n");
slirplog_error("Unknown ICMP code");
}
t->m_data += ICMP6_ERROR_MINLEN;
memcpy(t->m_data, m->m_data, error_data_len);
@ -419,7 +419,7 @@ void icmp6_input(struct mbuf *m)
icmp6_send_echoreply(m, slirp, ip, icmp);
} else {
/* TODO */
fprintf(stderr, "external icmpv6 not supported yet\n");
slirplog_error("external icmpv6 not supported yet");
}
break;

View File

@ -39,7 +39,7 @@ void ip6_input(struct mbuf *m)
DEBUG_ARG("m = %p", m);
DEBUG_ARG("m_len = %d", m->m_len);
if (m->m_len < sizeof(struct ip6)) {
if (m->m_len < (int)sizeof(struct ip6)) {
goto bad;
}
@ -49,7 +49,7 @@ void ip6_input(struct mbuf *m)
goto bad;
}
if (ntohs(ip6->ip_pl) + sizeof(struct ip6) > slirp->if_mtu) {
if (ntohs(ip6->ip_pl) + sizeof(struct ip6) > (unsigned)slirp->if_mtu) {
icmp6_send_error(m, ICMP6_TOOBIG, 0);
goto bad;
}
@ -57,7 +57,7 @@ void ip6_input(struct mbuf *m)
// Check if the message size is big enough to hold what's
// set in the payload length header. If not this is an invalid
// packet
if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) {
if (m->m_len < (int)(ntohs(ip6->ip_pl) + sizeof(struct ip6))) {
goto bad;
}

View File

@ -236,11 +236,25 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port);
#define SLIRP_HOSTFWD_UDP 1
#define SLIRP_HOSTFWD_V6ONLY 2
int slirp_add_hostxfwd(Slirp *slirp,
const struct sockaddr *haddr, socklen_t haddrlen,
const struct sockaddr *gaddr, socklen_t gaddrlen,
int flags);
int slirp_remove_hostxfwd(Slirp *slirp,
const struct sockaddr *haddr, socklen_t haddrlen,
int flags);
/* Set up port forwarding between a port in the guest network and a
* command running on the host */
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
/* Set up port forwarding between a port in the guest network and a
* Unix port on the host */
int slirp_add_unix(Slirp *slirp, const char *unixsock,
struct in_addr *guest_addr, int guest_port);
/* Set up port forwarding between a port in the guest network and a
* callback that will receive the data coming from the port */
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
@ -262,6 +276,12 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
/* Return a human-readable state of the slirp stack */
char *slirp_connection_info(Slirp *slirp);
/* Return a human-readable state of the NDP/ARP tables */
char *slirp_neighbor_info(Slirp *slirp);
/* Return the version of the slirp implementation */
const char *slirp_version_string(void);

View File

@ -91,6 +91,18 @@ int open_unix(struct socket *so, const char *unixpath)
return 0;
}
char *slirp_connection_info(Slirp *slirp)
{
/* not implemented */
return NULL;
}
char *slirp_neighbor_info(Slirp *slirp)
{
/* not implemented */
return NULL;
}
int slirp_bind_outbound(struct socket *so, unsigned short af)
{
int ret = 0;

View File

@ -145,7 +145,7 @@ static int ncsi_rsp_handler_oem(Slirp *slirp, const struct ncsi_pkt_hdr *nh,
}
/* Check for manufacturer id and Find the handler */
for (i = 0; i < SLIRP_N_ELEMENTS(ncsi_rsp_oem_handlers); i++) {
for (i = 0; i < (int)SLIRP_N_ELEMENTS(ncsi_rsp_oem_handlers); i++) {
if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
if (ncsi_rsp_oem_handlers[i].handler)
nrh = &ncsi_rsp_oem_handlers[i];
@ -280,7 +280,7 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
uint32_t checksum;
uint32_t *pchecksum;
if (pkt_len < ETH_HLEN + sizeof(struct ncsi_pkt_hdr)) {
if (pkt_len < (int)(ETH_HLEN + sizeof(struct ncsi_pkt_hdr))) {
return; /* packet too short */
}
@ -290,7 +290,7 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
memset(reh->h_source, 0xff, ETH_ALEN);
reh->h_proto = htons(ETH_P_NCSI);
for (i = 0; i < SLIRP_N_ELEMENTS(ncsi_rsp_handlers); i++) {
for (i = 0; i < (int)SLIRP_N_ELEMENTS(ncsi_rsp_handlers); i++) {
if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
handler = &ncsi_rsp_handlers[i];
break;

View File

@ -1343,6 +1343,7 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
addr_len = sizeof(addr);
if ((so->so_state & SS_HOSTFWD) &&
getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
addr_len == sizeof(addr) &&
addr.sin_family == AF_INET &&
addr.sin_addr.s_addr == host_addr.s_addr &&
addr.sin_port == port) {
@ -1374,6 +1375,83 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
return 0;
}
int slirp_remove_hostxfwd(Slirp *slirp,
const struct sockaddr *haddr, socklen_t haddrlen,
int flags)
{
struct socket *so;
struct socket *head = (flags & SLIRP_HOSTFWD_UDP ? &slirp->udb : &slirp->tcb);
struct sockaddr_storage addr;
socklen_t addr_len;
for (so = head->so_next; so != head; so = so->so_next) {
addr_len = sizeof(addr);
if ((so->so_state & SS_HOSTFWD) &&
getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
sockaddr_equal(&addr, (const struct sockaddr_storage *) haddr)) {
so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
closesocket(so->s);
sofree(so);
return 0;
}
}
return -1;
}
int slirp_add_hostxfwd(Slirp *slirp,
const struct sockaddr *haddr, socklen_t haddrlen,
const struct sockaddr *gaddr, socklen_t gaddrlen,
int flags)
{
struct sockaddr_in gdhcp_addr;
int fwd_flags = SS_HOSTFWD;
if (flags & SLIRP_HOSTFWD_V6ONLY)
fwd_flags |= SS_HOSTFWD_V6ONLY;
if (gaddr->sa_family == AF_INET) {
const struct sockaddr_in *gaddr_in = (const struct sockaddr_in *) gaddr;
if (gaddrlen < sizeof(struct sockaddr_in)) {
errno = EINVAL;
return -1;
}
if (!gaddr_in->sin_addr.s_addr) {
gdhcp_addr = *gaddr_in;
gdhcp_addr.sin_addr = slirp->vdhcp_startaddr;
gaddr = (struct sockaddr *) &gdhcp_addr;
gaddrlen = sizeof(gdhcp_addr);
}
} else {
if (gaddrlen < sizeof(struct sockaddr_in6)) {
errno = EINVAL;
return -1;
}
/*
* Libslirp currently only provides a stateless DHCPv6 server, thus
* we can't translate "addr-any" to the guest here. Instead, we defer
* performing the translation to when it's needed. See
* soassign_guest_addr_if_needed().
*/
}
if (flags & SLIRP_HOSTFWD_UDP) {
if (!udpx_listen(slirp, haddr, haddrlen,
gaddr, gaddrlen,
fwd_flags))
return -1;
} else {
if (!tcpx_listen(slirp, haddr, haddrlen,
gaddr, gaddrlen,
fwd_flags))
return -1;
}
return 0;
}
/* TODO: IPv6 */
static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
int guest_port)
@ -1474,6 +1552,7 @@ struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
{
struct socket *so;
/* TODO: IPv6 */
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
if (so->so_faddr.s_addr == guest_addr.s_addr &&
htons(so->so_fport) == guest_port) {
@ -1540,9 +1619,15 @@ void slirp_set_logfn(void *slirp, void *logfn, uint8_t debug_switches)
}
}
void slirplog_error(const char *msg)
void slirplog_error(const char *fmt, ...)
{
va_list ap;
char msg[512];
if (slirplog) {
va_start(ap, fmt);
vsprintf(msg, fmt, ap);
va_end(ap);
slirplog->error("%s", msg);
}
}

View File

@ -406,7 +406,7 @@ void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
void *slirp_timer_new(Slirp *slirp, SlirpTimerId id, void *cb_opaque);
/* Bochs addition */
void slirplog_error(const char *msg);
void slirplog_error(const char *fmt, ...) BX_CPP_AttrPrintf(1, 2);
void slirplog_debug(const char *fmt, ...) BX_CPP_AttrPrintf(1, 2);
#endif

View File

@ -296,7 +296,7 @@ err:
sofcantrcvmore(so);
tcp_sockclosed(sototcpcb(so));
fprintf(stderr, "soreadbuf buffer to small");
slirplog_error("soreadbuf buffer to small");
return -1;
}
@ -616,7 +616,7 @@ void sorecvfrom(struct socket *so)
IF_MAXLINKHDR + sizeof(struct ip6) + sizeof(struct udphdr);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
/*
@ -674,7 +674,7 @@ void sorecvfrom(struct socket *so)
icmp6_send_error(so->so_m, ICMP6_UNREACH, code);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
m_free(m);
}
@ -714,7 +714,7 @@ void sorecvfrom(struct socket *so)
ICMP6_UNREACH_ADDRESS);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
m_free(m);
return;
@ -732,7 +732,7 @@ void sorecvfrom(struct socket *so)
(struct sockaddr_in6 *)&daddr);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
} /* rx error */
} /* if ping packet */
@ -803,7 +803,7 @@ struct socket *tcpx_listen(Slirp *slirp,
break;
#endif
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
switch (laddr->sa_family) {
case AF_INET:
@ -814,7 +814,7 @@ struct socket *tcpx_listen(Slirp *slirp,
DEBUG_ARG("lport = %s", portstr);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
DEBUG_ARG("flags = %x", flags);
@ -1089,7 +1089,7 @@ void sotranslate_accept(struct socket *so)
s = slirp_socket(PF_INET, SOCK_DGRAM, 0);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
break;
}
if (s < 0) {
@ -1132,7 +1132,7 @@ unix2inet_cont:
s = slirp_socket(PF_INET6, SOCK_DGRAM, 0);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
break;
}
if (s < 0) {
@ -1163,7 +1163,7 @@ unix2inet6_cont:
so->so_fport6 = htons(slirp_rand_int_range(49152, 65536));
}
} else {
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
break;
} /* case AF_UNIX */
@ -1202,7 +1202,7 @@ int soassign_guest_addr_if_needed(struct socket *so)
switch (so->so_ffamily) {
case AF_INET:
if (so->so_laddr.s_addr == INADDR_ANY) {
fprintf(stderr, "Unsupported address\n");
slirplog_error("Unsupported address");
}
break;

View File

@ -146,7 +146,7 @@ static inline int sockaddr_equal(const struct sockaddr_storage *a,
}
#endif
default:
fprintf(stderr, "unknown protocol\n");
fprintf(stderr, "Unknown protocol\n");
}
return 0;
@ -165,7 +165,7 @@ static inline socklen_t sockaddr_size(const struct sockaddr_storage *a)
return sizeof(struct sockaddr_un);
#endif
default:
fprintf(stderr, "unknown protocol\n");
fprintf(stderr, "Unknown protocol\n");
}
return 0;

View File

@ -320,7 +320,7 @@ void tcp_input(struct mbuf *m, int iphlen, struct socket *inso,
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
@ -382,7 +382,7 @@ findso:
fhost6->sin6_port = ti->ti_dport;
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
@ -440,7 +440,7 @@ findso:
case AF_INET6:
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
}
@ -668,7 +668,7 @@ findso:
}
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
HTONL(ti->ti_seq); /* restore tcp header */
HTONL(ti->ti_ack);
@ -696,7 +696,7 @@ findso:
icmp6_send_error(m, ICMP6_UNREACH, code);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
}
tcp_close(tp);
@ -1530,7 +1530,7 @@ int tcp_mss(struct tcpcb *tp, unsigned offer)
sizeof(struct tcphdr) - sizeof(struct ip6);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
if (offer)
mss = MIN(mss, (int)offer);

View File

@ -480,7 +480,7 @@ send:
break;
default:
fprintf(stderr, "Unknown protocol");
slirplog_error("Unknown protocol");
}
if (error) {

View File

@ -89,7 +89,7 @@ void tcp_template(struct tcpcb *tp)
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
n->ti_seq = 0;
@ -146,7 +146,7 @@ void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
ti->ti.ti_i6.ih_x1 = 0;
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
flags = TH_ACK;
} else {
@ -175,7 +175,7 @@ void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
xchg(ti->ti_dport, ti->ti_sport, uint16_t);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
#undef xchg
}
@ -238,7 +238,7 @@ void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
}
@ -461,7 +461,7 @@ void tcp_connect(struct socket *inso)
addrlen = sizeof(struct sockaddr_in6);
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
ret = getnameinfo((const struct sockaddr *) &inso->lhost.ss, addrlen, addrstr, sizeof(addrstr), portstr, sizeof(portstr), NI_NUMERICHOST|NI_NUMERICSERV);
assert(ret == 0);

View File

@ -327,7 +327,7 @@ int udp_attach(struct socket *so, unsigned short af)
setsockopt(so->s, IPPROTO_IPV6, IPV6_RECVERR, &opt, sizeof(opt));
break;
default:
fprintf(stderr, "Unknown protocol\n");
slirplog_error("Unknown protocol");
}
}
#endif

View File

@ -45,4 +45,11 @@
# Enable IPv6 support (using default Qemu setup)
# ipv6_enabled = 1
# Enable slirp debugging support if > 0
# The value can be a combination of these debug levels
# 1 - "call" (function calls and arguments)
# 2 - "misc" (misc debug messages)
# 4 - "error" (normal errors)
# 8 - "tftp" (TFTP messages)
# 16 - "verbose_call" (more function calls)
# debug_switches = 1