Skip to content
Commits on Source (39)
[gitpublishprofile "default"]
base = master
to = slirp@lists.freedesktop.org
......@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v4.2.0] - 2020-03-17
### Added
- New API function `slirp_add_unix`: add a forward rule to a Unix socket.
- New API function `slirp_remove_guestfwd`: remove a forward rule previously
added by `slirp_add_exec`, `slirp_add_unix` or `slirp_add_guestfwd`
- New SlirpConfig.outbound_addr{,6} fields to bind output socket to a
specific address
### Changed
- socket: do not fallback on host loopback if get_dns_addr() failed
or the address is in slirp network
### Fixed
- ncsi: fix checksum OOB memory access
- `tcp_emu()`: fix OOB accesses
- tftp: restrict relative path access
- state: fix loading of guestfwd state
## [4.1.0] - 2019-12-02
### Added
......@@ -51,5 +73,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- License clarifications.
[unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...master
[4.2.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...v4.2.0
[4.1.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.0.0...v4.1.0
[4.0.0]: https://gitlab.freedesktop.org/slirp/libslirp/commits/v4.0.0
......@@ -3,7 +3,7 @@ BUILD_DIR ?= .
LIBSLIRP = $(BUILD_DIR)/libslirp.a
SLIRP_MAJOR_VERSION = 4
SLIRP_MINOR_VERSION = 1
SLIRP_MINOR_VERSION = 2
SLIRP_MICRO_VERSION = 0
all: $(LIBSLIRP)
......
project('libslirp', 'c',
version : '4.1.0',
version : '4.2.0',
license : 'BSD-3-Clause',
default_options : ['warning_level=1', 'c_std=gnu99']
)
......@@ -32,9 +32,9 @@ conf.set('SLIRP_MICRO_VERSION', micro_version)
# - If the interface is the same as the previous version, but bugs are
# fixed, change:
# REVISION += 1
lt_current = 1
lt_current = 2
lt_revision = 0
lt_age = 1
lt_age = 2
lt_version = '@0@.@1@.@2@'.format(lt_current - lt_age, lt_age, lt_revision)
host_system = host_machine.system()
......
......@@ -254,9 +254,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
*q++ = DHCPACK;
}
if (slirp->bootp_filename)
snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
slirp->bootp_filename);
if (slirp->bootp_filename) {
g_assert(strlen(slirp->bootp_filename) < sizeof(rbp->bp_file));
strcpy(rbp->bp_file, slirp->bootp_filename);
}
*q++ = RFC2132_SRV_ID;
*q++ = 4;
......
......@@ -113,7 +113,7 @@ struct bootp_t {
struct in_addr bp_giaddr;
uint8_t bp_hwaddr[16];
uint8_t bp_sname[64];
uint8_t bp_file[128];
char bp_file[128];
uint8_t bp_vend[DHCP_OPT_LEN];
};
......
......@@ -179,13 +179,12 @@ static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
*resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
*resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);
slen = snprintf((char *)resp + 2, smaxlen,
"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
sa[15], slirp->bootp_filename);
slen = MIN(slen, smaxlen);
slen = slirp_fmt((char *)resp + 2, smaxlen,
"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
sa[15], slirp->bootp_filename);
*resp++ = slen >> 8; /* option-len high byte */
*resp++ = slen; /* option-len low byte */
resp += slen;
......
......@@ -90,6 +90,13 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
return -1;
}
if (slirp_bind_outbound(so, AF_INET) != 0) {
// bind failed - close socket
closesocket(so->s);
so->s = -1;
return -1;
}
so->so_m = m;
so->so_faddr = ip->ip_dst;
so->so_laddr = ip->ip_src;
......
......@@ -67,7 +67,7 @@ typedef struct SlirpCb {
} SlirpCb;
#define SLIRP_CONFIG_VERSION_MIN 1
#define SLIRP_CONFIG_VERSION_MAX 1
#define SLIRP_CONFIG_VERSION_MAX 2
typedef struct SlirpConfig {
/* Version must be provided */
......@@ -107,6 +107,8 @@ typedef struct SlirpConfig {
/*
* Fields introduced in SlirpConfig version 2 begin
*/
struct sockaddr_in *outbound_addr;
struct sockaddr_in6 *outbound_addr6;
} SlirpConfig;
Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks,
......@@ -138,8 +140,13 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port);
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
int slirp_add_unix(Slirp *slirp, const char *unixsock,
struct in_addr *guest_addr, int guest_port);
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port);
/* remove entries added by slirp_add_exec, slirp_add_unix or slirp_add_guestfwd */
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
char *slirp_connection_info(Slirp *slirp);
......
......@@ -23,3 +23,8 @@ local:
SLIRP_4.1 {
slirp_new;
} SLIRP_4.0;
SLIRP_4.2 {
slirp_add_unix;
slirp_remove_guestfwd;
} SLIRP_4.1;
......@@ -4,6 +4,9 @@
*/
#include "slirp.h"
#ifdef G_OS_UNIX
#include <sys/un.h>
#endif
inline void insque(void *a, void *b)
{
......@@ -50,6 +53,30 @@ struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
return f;
}
struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
struct in_addr addr, int port)
{
struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
f->ex_unix = g_strdup(unixsock);
return f;
}
int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port)
{
for (; *ex_ptr != NULL; ex_ptr = &((*ex_ptr)->ex_next)) {
struct gfwd_list *f = *ex_ptr;
if (f->ex_addr.s_addr == addr.s_addr && f->ex_fport == port) {
*ex_ptr = f->ex_next;
g_free(f->ex_exec);
g_free(f);
return 0;
}
}
return -1;
}
static int slirp_socketpair_with_oob(int sv[2])
{
struct sockaddr_in addr = {
......@@ -210,6 +237,45 @@ int fork_exec(struct socket *so, const char *ex)
return 1;
}
int open_unix(struct socket *so, const char *unixpath)
{
#ifdef G_OS_UNIX
struct sockaddr_un sa;
int s;
DEBUG_CALL("open_unix");
DEBUG_ARG("so = %p", so);
DEBUG_ARG("unixpath = %s", unixpath);
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
if (g_strlcpy(sa.sun_path, unixpath, sizeof(sa.sun_path)) >= sizeof(sa.sun_path)) {
g_critical("Bad unix path: %s", unixpath);
return 0;
}
s = slirp_socket(PF_UNIX, SOCK_STREAM, 0);
if (s < 0) {
g_critical("open_unix(): %s", strerror(errno));
return 0;
}
if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
g_critical("open_unix(): %s", strerror(errno));
closesocket(s);
return 0;
}
so->s = s;
slirp_set_nonblock(so->s);
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
return 1;
#else
g_assert_not_reached();
#endif
}
char *slirp_connection_info(Slirp *slirp)
{
GString *str = g_string_new(NULL);
......@@ -254,7 +320,7 @@ char *slirp_connection_info(Slirp *slirp)
dst_addr = so->so_faddr;
dst_port = so->so_fport;
}
snprintf(buf, sizeof(buf), " TCP[%s]", state);
slirp_fmt0(buf, sizeof(buf), " TCP[%s]", state);
g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
"*",
......@@ -266,14 +332,14 @@ char *slirp_connection_info(Slirp *slirp)
for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
if (so->so_state & SS_HOSTFWD) {
snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]");
slirp_fmt0(buf, sizeof(buf), " UDP[HOST_FORWARD]");
src_len = sizeof(src);
getsockname(so->s, (struct sockaddr *)&src, &src_len);
dst_addr = so->so_laddr;
dst_port = so->so_lport;
} else {
snprintf(buf, sizeof(buf), " UDP[%d sec]",
(so->so_expire - curtime) / 1000);
slirp_fmt0(buf, sizeof(buf), " UDP[%d sec]",
(so->so_expire - curtime) / 1000);
src.sin_addr = so->so_laddr;
src.sin_port = so->so_lport;
dst_addr = so->so_faddr;
......@@ -289,8 +355,8 @@ char *slirp_connection_info(Slirp *slirp)
}
for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
snprintf(buf, sizeof(buf), " ICMP[%d sec]",
(so->so_expire - curtime) / 1000);
slirp_fmt0(buf, sizeof(buf), " ICMP[%d sec]",
(so->so_expire - curtime) / 1000);
src.sin_addr = so->so_laddr;
dst_addr = so->so_faddr;
g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s,
......@@ -302,3 +368,23 @@ char *slirp_connection_info(Slirp *slirp)
return g_string_free(str, FALSE);
}
int slirp_bind_outbound(struct socket *so, unsigned short af)
{
int ret = 0;
struct sockaddr *addr = NULL;
int addr_size = 0;
if (af == AF_INET && so->slirp->outbound_addr != NULL) {
addr = (struct sockaddr *)so->slirp->outbound_addr;
addr_size = sizeof(struct sockaddr_in);
} else if (af == AF_INET6 && so->slirp->outbound_addr6 != NULL) {
addr = (struct sockaddr *)so->slirp->outbound_addr6;
addr_size = sizeof(struct sockaddr_in6);
}
if (addr != NULL) {
ret = bind(so->s, addr, addr_size);
}
return ret;
}
\ No newline at end of file
......@@ -14,6 +14,7 @@ struct gfwd_list {
struct in_addr ex_addr; /* Server address */
int ex_fport; /* Port to telnet to */
char *ex_exec; /* Command line of what to exec */
char *ex_unix; /* unix socket */
struct gfwd_list *ex_next;
};
......@@ -53,6 +54,7 @@ struct slirp_quehead {
void slirp_insque(void *, void *);
void slirp_remque(void *);
int fork_exec(struct socket *so, const char *ex);
int open_unix(struct socket *so, const char *unixsock);
struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
void *opaque, struct in_addr addr, int port);
......@@ -60,4 +62,11 @@ struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
struct in_addr addr, int port);
struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
struct in_addr addr, int port);
int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port);
int slirp_bind_outbound(struct socket *so, unsigned short af);
#endif
......@@ -47,7 +47,7 @@ static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
* 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
* payload interpreted as a series of 16-bit unsigned integer values.
*/
for (i = 0; i < len; i++) {
for (i = 0; i < len / 2; i++) {
checksum += htons(data[i]);
}
......
......@@ -278,6 +278,9 @@ Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
g_return_val_if_fail(cfg->if_mtu <= IF_MTU_MAX, NULL);
g_return_val_if_fail(cfg->if_mru >= IF_MRU_MIN || cfg->if_mru == 0, NULL);
g_return_val_if_fail(cfg->if_mru <= IF_MRU_MAX, NULL);
g_return_val_if_fail(!cfg->bootfile ||
(strlen(cfg->bootfile) <
G_SIZEOF_MEMBER(struct bootp_t, bp_file)), NULL);
slirp = g_malloc0(sizeof(Slirp));
......@@ -323,6 +326,13 @@ Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
slirp->disable_host_loopback = cfg->disable_host_loopback;
slirp->enable_emu = cfg->enable_emu;
if (cfg->version >= 2) {
slirp->outbound_addr = cfg->outbound_addr;
slirp->outbound_addr6 = cfg->outbound_addr6;
} else {
slirp->outbound_addr = NULL;
slirp->outbound_addr6 = NULL;
}
return slirp;
}
......@@ -368,6 +378,7 @@ void slirp_cleanup(Slirp *slirp)
for (e = slirp->guestfwd_list; e; e = next) {
next = e->ex_next;
g_free(e->ex_exec);
g_free(e->ex_unix);
g_free(e);
}
......@@ -1049,6 +1060,22 @@ int slirp_add_exec(Slirp *slirp, const char *cmdline,
return 0;
}
int slirp_add_unix(Slirp *slirp, const char *unixsock,
struct in_addr *guest_addr, int guest_port)
{
#ifdef G_OS_UNIX
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
return -1;
}
add_unix(&slirp->guestfwd_list, unixsock, *guest_addr, htons(guest_port));
return 0;
#else
g_warn_if_reached();
return -1;
#endif
}
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port)
{
......@@ -1061,6 +1088,13 @@ int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
return 0;
}
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port)
{
return remove_guestfwd(&slirp->guestfwd_list, guest_addr,
htons(guest_port));
}
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
if (so->s == -1 && so->guestfwd) {
......
......@@ -199,6 +199,9 @@ struct Slirp {
const SlirpCb *cb;
void *opaque;
struct sockaddr_in *outbound_addr;
struct sockaddr_in6 *outbound_addr6;
};
void if_start(Slirp *);
......
......@@ -819,66 +819,65 @@ void sofwdrain(struct socket *so)
sofcantsendmore(so);
}
static bool sotranslate_out4(Slirp *s, struct socket *so, struct sockaddr_in *sin)
{
if (so->so_faddr.s_addr == s->vnameserver_addr.s_addr) {
return get_dns_addr(&sin->sin_addr) >= 0;
}
if (so->so_faddr.s_addr == s->vhost_addr.s_addr ||
so->so_faddr.s_addr == 0xffffffff) {
if (s->disable_host_loopback) {
return false;
}
sin->sin_addr = loopback_addr;
}
return true;
}
static bool sotranslate_out6(Slirp *s, struct socket *so, struct sockaddr_in6 *sin)
{
if (in6_equal(&so->so_faddr6, &s->vnameserver_addr6)) {
return get_dns6_addr(&sin->sin6_addr, &sin->sin6_scope_id) >= 0;
}
if (in6_equal_net(&so->so_faddr6, &s->vprefix_addr6, s->vprefix_len) ||
in6_equal(&so->so_faddr6, &(struct in6_addr)ALLNODES_MULTICAST)) {
if (s->disable_host_loopback) {
return false;
}
sin->sin6_addr = in6addr_loopback;
}
return true;
}
/*
* Translate addr in host addr when it is a virtual address
*/
int sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
{
int rc = 0;
Slirp *slirp = so->slirp;
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
bool ok = true;
switch (addr->ss_family) {
case AF_INET:
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
slirp->vnetwork_addr.s_addr) {
/* It's an alias */
if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
if (get_dns_addr(&sin->sin_addr) >= 0) {
goto ret;
}
}
if (slirp->disable_host_loopback) {
rc = -1;
errno = EPERM;
goto ret;
} else {
sin->sin_addr = loopback_addr;
}
} else if (!slirp->disable_host_loopback && so->so_faddr.s_addr == 0xffffffff) {
/* Receive broadcast as well */
sin->sin_addr = loopback_addr;
}
ok = sotranslate_out4(so->slirp, so, (struct sockaddr_in *)addr);
break;
case AF_INET6:
if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
slirp->vprefix_len)) {
if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
uint32_t scope_id;
if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) {
sin6->sin6_scope_id = scope_id;
goto ret;
}
}
if (slirp->disable_host_loopback) {
rc = -1;
errno = EPERM;
goto ret;
} else {
sin6->sin6_addr = in6addr_loopback;
}
} else if (!slirp->disable_host_loopback
&& in6_equal(&so->so_faddr6, &(struct in6_addr) ALLNODES_MULTICAST)) {
sin6->sin6_addr = in6addr_loopback;
}
ok = sotranslate_out6(so->slirp, so, (struct sockaddr_in6 *)addr);
break;
}
default:
break;
if (!ok) {
errno = EPERM;
return -1;
}
ret:
return rc;
return 0;
}
void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
......
......@@ -366,6 +366,8 @@ int slirp_state_load(Slirp *slirp, int version_id, SlirpReadCb read_cb,
if (!ex_ptr) {
return -EINVAL;
}
so->guestfwd = ex_ptr;
}
return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id);
......
......@@ -406,6 +406,16 @@ int tcp_fconnect(struct socket *so, unsigned short af)
DEBUG_ARG("so = %p", so);
ret = so->s = slirp_socket(af, SOCK_STREAM, 0);
if (ret >= 0) {
ret = slirp_bind_outbound(so, af);
if (ret < 0) {
// bind failed - close socket
closesocket(so->s);
so->s = -1;
return (ret);
}
}
if (ret >= 0) {
int opt, s = so->s;
struct sockaddr_storage addr;
......@@ -575,6 +585,9 @@ uint8_t tcp_tos(struct socket *so)
* more checks are needed here
*
* XXX Assumes the whole command came in one packet
* XXX If there is more than one command in the packet, the others may
* be truncated.
* XXX If the command is too long, it may be truncated.
*
* XXX Some ftp clients will have their TOS set to
* LOWDELAY and so Nagel will kick in. Because of this,
......@@ -639,9 +652,8 @@ int tcp_emu(struct socket *so, struct mbuf *m)
}
NTOHS(n1);
NTOHS(n2);
m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1);
m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
assert(m->m_len < M_ROOM(m));
m_inc(m, g_snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1);
m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
} else {
*eol = '\r';
}
......@@ -681,9 +693,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
n4 = (laddr & 0xff);
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len += snprintf(bptr, m->m_size - m->m_len,
"ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4,
n5, n6, x == 7 ? buff : "");
m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
"ORT %d,%d,%d,%d,%d,%d\r\n%s",
n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
return 1;
} else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
/*
......@@ -716,11 +728,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
n4 = (laddr & 0xff);
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len +=
snprintf(bptr, m->m_size - m->m_len,
"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
return 1;
}
......@@ -743,8 +753,8 @@ int tcp_emu(struct socket *so, struct mbuf *m)
if (m->m_data[m->m_len - 1] == '\0' && lport != 0 &&
(so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
htons(lport), SS_FACCEPTONCE)) != NULL)
m->m_len =
snprintf(m->m_data, m->m_size, "%d", ntohs(so->so_fport)) + 1;
m->m_len = slirp_fmt0(m->m_data, M_ROOM(m),
"%d", ntohs(so->so_fport));
return 1;
case EMU_IRC:
......@@ -763,9 +773,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
return 1;
}
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len += snprintf(bptr, m->m_size, "DCC CHAT chat %lu %u%c\n",
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), 1);
m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
"DCC CHAT chat %lu %u%c\n",
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), 1);
} else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport,
&n1) == 4) {
if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
......@@ -773,10 +784,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
return 1;
}
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len +=
snprintf(bptr, m->m_size, "DCC SEND %s %lu %u %u%c\n", buff,
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
"DCC SEND %s %lu %u %u%c\n", buff,
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
} else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport,
&n1) == 4) {
if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
......@@ -784,10 +795,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
return 1;
}
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len +=
snprintf(bptr, m->m_size, "DCC MOVE %s %lu %u %u%c\n", buff,
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
"DCC MOVE %s %lu %u %u%c\n", buff,
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
}
return 1;
......@@ -871,6 +882,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
break;
case 5:
if (bptr == m->m_data + m->m_len - 1)
return 1; /* We need two bytes */
/*
* The difference between versions 1.0 and
* 2.0 is here. For future versions of
......@@ -886,6 +900,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
/* This is the field containing the port
* number that RA-player is listening to.
*/
if (bptr == m->m_data + m->m_len - 1)
return 1; /* We need two bytes */
lport = (((uint8_t *)bptr)[0] << 8) + ((uint8_t *)bptr)[1];
if (lport < 6970)
lport += 256; /* don't know why */
......@@ -948,13 +966,15 @@ int tcp_ctl(struct socket *so)
return 1;
}
DEBUG_MISC(" executing %s", ex_ptr->ex_exec);
return fork_exec(so, ex_ptr->ex_exec);
if (ex_ptr->ex_unix)
return open_unix(so, ex_ptr->ex_unix);
else
return fork_exec(so, ex_ptr->ex_exec);
}
}
}
sb->sb_cc =
snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
"Error: No application configured.\r\n");
sb->sb_cc = slirp_fmt(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
"Error: No application configured.\r\n");
sb->sb_wptr += sb->sb_cc;
return 0;
}
......@@ -185,16 +185,11 @@ static int tftp_send_oack(struct tftp_session *spt, const char *keys[],
tp->tp_op = htons(TFTP_OACK);
for (i = 0; i < nb; i++) {
n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
keys[i]) +
1;
n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
values[i]) +
1;
n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", keys[i]);
n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", values[i]);
}
m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n -
sizeof(struct udphdr);
m->m_len = G_SIZEOF_MEMBER(struct tftp_t, tp_op) + n;
tftp_udp_output(spt, m, recv_tp);
return 0;
......@@ -344,8 +339,13 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
k += 6; /* skipping octet */
/* do sanity checks on the filename */
if (!strncmp(req_fname, "../", 3) ||
req_fname[strlen(req_fname) - 1] == '/' || strstr(req_fname, "/../")) {
if (
#ifdef G_OS_WIN32
strstr(req_fname, "..\\") ||
req_fname[strlen(req_fname) - 1] == '\\' ||
#endif
strstr(req_fname, "../") ||
req_fname[strlen(req_fname) - 1] == '/') {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
......
......@@ -279,6 +279,12 @@ int udp_attach(struct socket *so, unsigned short af)
{
so->s = slirp_socket(af, SOCK_DGRAM, 0);
if (so->s != -1) {
if (slirp_bind_outbound(so, af) != 0) {
// bind failed - close socket
closesocket(so->s);
so->s = -1;
return -1;
}
so->so_expire = curtime + SO_EXPIRE;
insque(so, &so->slirp->udb);
}
......