Skip to content
Commits on Source (26)
image: fedora:latest
variables:
DEPS: meson ninja-build make
DEPS: meson ninja-build
gcc pkg-config glib2-devel
mingw64-gcc mingw64-pkg-config mingw64-glib2
clang-analyzer git-core
before_script:
- dnf install -y $DEPS
- git fetch --tags https://gitlab.freedesktop.org/slirp/libslirp.git
- git describe
build:
......@@ -22,6 +23,21 @@ build-mingw64:
- (mkdir buildw && cd buildw && mingw64-meson --werror) || (cat buildw/meson-logs/meson-log.txt && exit 1)
- ninja -C buildw
build-qemu:
Coverity:
only:
refs:
- master
- coverity
script:
- make BUILD_DIR=build
- dnf update -y
- dnf install -y curl clang
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
- tar xfz /tmp/cov-analysis-linux64.tgz
- CC=clang meson build
- cov-analysis-linux64-*/bin/cov-build --dir cov-int ninja -C build
- tar cfz cov-int.tar.gz cov-int
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID "
......@@ -5,6 +5,26 @@ 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).
## [4.4.0] - 2020-12-02
### Added
- udp, udp6, icmp: handle TTL value. !48
- Enable forwarding ICMP errors. !49
- Add DNS resolving for iOS. !54
### Changed
- Improve meson subproject() support. !53
- Removed Makefile-based build system. !56
### Fixed
- socket: consume empty packets. !55
- check pkt_len before reading protocol header (CVE-2020-29129). !57
- ip_stripoptions use memmove (fixes undefined behaviour). !47
- various Coverity-related changes/fixes.
## [4.3.1] - 2020-07-08
### Changed
......@@ -104,6 +124,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Standalone project, removing any QEMU dependency.
- License clarifications.
[4.4.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.1...v4.4.0
[4.3.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.0...v4.3.1
[4.3.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.2.0...v4.3.0
[4.2.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...v4.2.0
......
ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
BUILD_DIR ?= .
LIBSLIRP = $(BUILD_DIR)/libslirp.a
SLIRP_MAJOR_VERSION = 4
SLIRP_MINOR_VERSION = 3
SLIRP_MICRO_VERSION = 1
SLIRP_VERSION_STRING = "$(SLIRP_MAJOR_VERSION).$(SLIRP_MINOR_VERSION).$(SLIRP_MICRO_VERSION)-git"
all: $(LIBSLIRP)
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:%.o=%.d)
INC_DIRS := $(BUILD_DIR)/src
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
override CFLAGS += \
-DG_LOG_DOMAIN='"Slirp"' \
$(shell $(PKG_CONFIG) --cflags glib-2.0) \
$(INC_FLAGS) \
-MMD -MP
override LDFLAGS += $(shell $(PKG_CONFIG) --libs glib-2.0)
$(BUILD_DIR)/src/libslirp-version.h: Makefile
@$(MKDIR_P) $(dir $@)
$(call quiet-command,cat $(ROOT_DIR)/src/libslirp-version.h.in | \
sed 's/@SLIRP_MAJOR_VERSION@/$(SLIRP_MAJOR_VERSION)/' | \
sed 's/@SLIRP_MINOR_VERSION@/$(SLIRP_MINOR_VERSION)/' | \
sed 's/@SLIRP_MICRO_VERSION@/$(SLIRP_MICRO_VERSION)/' | \
sed 's/@SLIRP_VERSION_STRING@/$(SLIRP_VERSION_STRING)/' \
> $@,"GEN","$@")
$(OBJS): $(BUILD_DIR)/src/libslirp-version.h
$(LIBSLIRP): $(OBJS)
.PHONY: clean
clean:
rm -r $(OBJS) $(DEPS) $(LIBSLIRP) $(BUILD_DIR)/src/libslirp-version.h
$(BUILD_DIR)/src/%.o: $(ROOT_DIR)/src/%.c
@$(MKDIR_P) $(dir $@)
$(call quiet-command,$(CC) $(CFLAGS) -c -o $@ $<,"CC","$@")
%.a:
$(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"AR","$@")
PKG_CONFIG ?= pkg-config
MKDIR_P ?= mkdir -p
quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1
quiet-@ = $(if $(V),,@)
quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
print-%:
@echo '$*=$($*)'
.SUFFIXES:
-include $(DEPS)
......@@ -7,7 +7,7 @@ containers or various tools.
### Prerequisites
A C compiler, make/meson and glib2 development libraries.
A C compiler, meson and glib2 development libraries.
(see also [.gitlab-ci.yml](.gitlab-ci.yml) DEPS variable for the list
of dependencies on Fedora)
......
#!/bin/bash
set -e
set -o pipefail
if test "$1" = ""; then
echo "Version not provided" >&2
exit 1
fi
if ! test -d "$2"; then
echo "Source directory not provided" >&2
exit 1
fi
# generate tarball version
echo "$1" > "$MESON_DIST_ROOT/.tarball-version"
project('libslirp', 'c',
version : run_command('build-aux/git-version-gen', '@0@/.tarball-version'.format(meson.source_root()), check : true).stdout().strip(),
version : '4.4.0',
license : 'BSD-3-Clause',
default_options : ['warning_level=1', 'c_std=gnu99'],
meson_version : '>= 0.49',
meson_version : '>= 0.50',
)
meson.add_dist_script('build-aux/meson-dist', meson.project_version(), meson.source_root())
version = meson.project_version()
varr = version.split('.')
major_version = varr[0]
......@@ -17,7 +15,17 @@ conf = configuration_data()
conf.set('SLIRP_MAJOR_VERSION', major_version)
conf.set('SLIRP_MINOR_VERSION', minor_version)
conf.set('SLIRP_MICRO_VERSION', micro_version)
conf.set_quoted('SLIRP_VERSION_STRING', version)
full_version = run_command('build-aux/git-version-gen',
'@0@/.tarball-version'.format(meson.current_source_dir()),
check : true).stdout().strip()
if full_version.startswith('UNKNOWN')
full_version = meson.project_version()
elif not full_version.startswith(meson.project_version())
error('meson.build project version @0@ does not match git-describe output @1@'
.format(meson.project_version(), full_version))
endif
conf.set_quoted('SLIRP_VERSION_STRING', full_version + get_option('version_suffix'))
# libtool versioning - this applies to libslirp
#
......@@ -37,7 +45,7 @@ conf.set_quoted('SLIRP_VERSION_STRING', version)
# fixed, change:
# REVISION += 1
lt_current = 2
lt_revision = 2
lt_revision = 3
lt_age = 2
lt_version = '@0@.@1@.@2@'.format(lt_current - lt_age, lt_age, lt_revision)
......@@ -54,6 +62,10 @@ if host_system == 'windows'
cc.find_library('ws2_32'),
cc.find_library('iphlpapi')
]
elif host_system == 'darwin'
platform_deps += [
cc.find_library('resolv')
]
endif
cargs = [
......@@ -95,11 +107,18 @@ sources = [
]
mapfile = 'src/libslirp.map'
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
vflag = []
vflag_test = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
if cc.has_link_argument(vflag_test)
vflag += vflag_test
endif
install_devel = not meson.is_subproject()
configure_file(
input : 'src/libslirp-version.h.in',
output : 'libslirp-version.h',
install : install_devel,
install_dir : join_paths(get_option('includedir'), 'slirp'),
configuration : conf
)
......@@ -110,25 +129,30 @@ lib = library('slirp', sources,
link_args : vflag,
link_depends : mapfile,
dependencies : [glib_dep, platform_deps],
install : true
install : install_devel or get_option('default_library') == 'shared',
)
libslirp_dep = declare_dependency(
include_directories: include_directories('.', 'src'),
link_with: lib)
install_headers(['src/libslirp.h'], subdir : 'slirp')
pkg = import('pkgconfig')
pkg.generate(
version : version,
libraries : lib,
requires : [
'glib-2.0',
],
name : 'slirp',
description : 'User-space network stack',
filebase : 'slirp',
subdirs : 'slirp',
)
if install_devel
install_headers(['src/libslirp.h'], subdir : 'slirp')
pkg = import('pkgconfig')
pkg.generate(
version : version,
libraries : lib,
requires : [
'glib-2.0',
],
name : 'slirp',
description : 'User-space network stack',
filebase : 'slirp',
subdirs : 'slirp',
)
else
if get_option('default_library') == 'both'
lib = lib.get_static_lib()
endif
libslirp_dep = declare_dependency(
include_directories: include_directories('.', 'src'),
link_with: lib)
endif
option('version_suffix', type: 'string', value: '',
description: 'Suffix to append to SLIRP_VERSION_STRING')
......@@ -69,7 +69,7 @@ static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
ip6_output(NULL, t, 0);
}
void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
void icmp6_forward_error(struct mbuf *m, uint8_t type, uint8_t code, struct in6_addr *src)
{
Slirp *slirp = m->slirp;
struct mbuf *t;
......@@ -88,7 +88,7 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
/* IPv6 packet */
struct ip6 *rip = mtod(t, struct ip6 *);
rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
rip->ip_src = *src;
rip->ip_dst = ip->ip_src;
inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
DEBUG_ARG("target = %s", addrstr);
......@@ -131,6 +131,12 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
ip6_output(NULL, t, 0);
}
void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
{
struct in6_addr src = LINKLOCAL_ADDR;
icmp6_forward_error(m, type, code, &src);
}
/*
* Send NDP Router Advertisement
*/
......
......@@ -212,6 +212,7 @@ struct ndpopt {
void icmp6_init(Slirp *slirp);
void icmp6_cleanup(Slirp *slirp);
void icmp6_input(struct mbuf *);
void icmp6_forward_error(struct mbuf *m, uint8_t type, uint8_t code, struct in6_addr *src);
void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code);
void ndp_send_ra(Slirp *slirp);
void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
......
......@@ -176,6 +176,8 @@ void icmp_input(struct mbuf *m, int hlen)
} else {
struct socket *so;
struct sockaddr_storage addr;
int ttl;
so = socreate(slirp);
if (icmp_send(so, m, hlen) == 0) {
return;
......@@ -207,6 +209,19 @@ void icmp_input(struct mbuf *m, int hlen)
return;
}
/*
* Check for TTL
*/
ttl = ip->ip_ttl-1;
if (ttl <= 0) {
DEBUG_MISC("udp ttl exceeded");
icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0,
NULL);
udp_detach(so);
break;
}
setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
if (sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
(struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s", errno,
......@@ -256,8 +271,8 @@ end_error:
*/
#define ICMP_MAXDATALEN (IP_MSS - 28)
void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message)
void icmp_forward_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message, struct in_addr *src)
{
unsigned hlen, shlen, s_ip_len;
register struct ip *ip;
......@@ -372,7 +387,7 @@ void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
ip->ip_ttl = MAXTTL;
ip->ip_p = IPPROTO_ICMP;
ip->ip_dst = ip->ip_src; /* ip addresses */
ip->ip_src = m->slirp->vhost_addr;
ip->ip_src = *src;
(void)ip_output((struct socket *)NULL, m);
......@@ -381,6 +396,12 @@ end_error:
}
#undef ICMP_MAXDATALEN
void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message)
{
icmp_forward_error(msrc, type, code, minsize, message, &msrc->slirp->vhost_addr);
}
/*
* Reflect the ip packet back to the source
*/
......
......@@ -157,6 +157,8 @@ struct icmp {
void icmp_init(Slirp *slirp);
void icmp_cleanup(Slirp *slirp);
void icmp_input(struct mbuf *, int);
void icmp_forward_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message, struct in_addr *src);
void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message);
void icmp_reflect(struct mbuf *);
......
......@@ -454,7 +454,7 @@ void ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
olen = (ip->ip_hl << 2) - sizeof(struct ip);
opts = (char *)(ip + 1);
i = m->m_len - (sizeof(struct ip) + olen);
memcpy(opts, opts + olen, (unsigned)i);
memmove(opts, opts + olen, (unsigned)i);
m->m_len -= olen;
ip->ip_hl = sizeof(struct ip) >> 2;
......
......@@ -148,6 +148,10 @@ 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)) {
return; /* packet too short */
}
memset(ncsi_reply, 0, sizeof(ncsi_reply));
memset(reh->h_dest, 0xff, ETH_ALEN);
......
......@@ -64,7 +64,7 @@ static unsigned dns6_addr_time;
/* for the aging of certain requests like DNS */
#define TIMEOUT_DEFAULT 1000 /* milliseconds */
#ifdef _WIN32
#if defined(_WIN32)
int get_dns_addr(struct in_addr *pdns_addr)
{
......@@ -121,7 +121,104 @@ static void winsock_cleanup(void)
WSACleanup();
}
#else
#elif defined(__APPLE__)
#include <resolv.h>
static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
socklen_t addrlen, unsigned *cached_time)
{
struct stat old_stat;
if (curtime - *cached_time < TIMEOUT_DEFAULT) {
memcpy(pdns_addr, cached_addr, addrlen);
return 0;
}
return 1;
}
static int get_dns_addr_libresolv(int af, void *pdns_addr, void *cached_addr,
socklen_t addrlen, uint32_t *scope_id,
unsigned *cached_time)
{
char buff[512];
struct __res_state state;
union res_sockaddr_union servers[NI_MAXSERV];
int count;
int found;
if (res_ninit(&state) != 0) {
return -1;
}
count = res_getservers(&state, servers, NI_MAXSERV);
found = 0;
DEBUG_MISC("IP address of your DNS(s):");
for (int i = 0; i < count; i++) {
if (af == servers[i].sin.sin_family) {
found++;
}
// we use the first found entry
if (found == 1) {
memcpy(pdns_addr, &servers[i].sin.sin_addr, addrlen);
memcpy(cached_addr, &servers[i].sin.sin_addr, addrlen);
if (scope_id) {
*scope_id = 0;
}
*cached_time = curtime;
}
if (found > 3) {
DEBUG_MISC(" (more)");
break;
} else if (slirp_debug & DBG_MISC) {
char s[INET6_ADDRSTRLEN];
const char *res = inet_ntop(servers[i].sin.sin_family,
&servers[i].sin.sin_addr,
s,
sizeof(s));
if (!res) {
res = " (string conversion error)";
}
DEBUG_MISC(" %s", res);
}
}
res_nclose(&state);
if (!found)
return -1;
return 0;
}
int get_dns_addr(struct in_addr *pdns_addr)
{
if (dns_addr.s_addr != 0) {
int ret;
ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr),
&dns_addr_time);
if (ret <= 0) {
return ret;
}
}
return get_dns_addr_libresolv(AF_INET, pdns_addr, &dns_addr,
sizeof(dns_addr), NULL, &dns_addr_time);
}
int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
{
if (!in6_zero(&dns6_addr)) {
int ret;
ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr),
&dns6_addr_time);
if (ret <= 0) {
return ret;
}
}
return get_dns_addr_libresolv(AF_INET6, pdns6_addr, &dns6_addr,
sizeof(dns6_addr), scope_id, &dns6_addr_time);
}
#else // !defined(_WIN32) && !defined(__APPLE__)
static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
socklen_t addrlen, struct stat *cached_stat,
......@@ -763,6 +860,10 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
return;
}
if (pkt_len < ETH_HLEN + sizeof(struct slirp_arphdr)) {
return; /* packet too short */
}
ar_op = ntohs(ah->ar_op);
switch (ar_op) {
case ARPOP_REQUEST:
......
......@@ -8,6 +8,9 @@
#ifdef __sun__
#include <sys/filio.h>
#endif
#ifdef __linux__
#include <linux/errqueue.h>
#endif
static void sofcantrcvmore(struct socket *so);
static void sofcantsendmore(struct socket *so);
......@@ -336,8 +339,8 @@ int sosendoob(struct socket *so)
DEBUG_ARG("so = %p", so);
DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
if (so->so_urgc > 2048)
so->so_urgc = 2048; /* XXXX */
if (so->so_urgc > sizeof(buff))
so->so_urgc = sizeof(buff); /* XXXX */
if (sb->sb_rptr < sb->sb_wptr) {
/* We can send it directly */
......@@ -349,7 +352,7 @@ int sosendoob(struct socket *so)
* we must copy all data to a linear buffer then
* send it all
*/
uint32_t urgc = so->so_urgc;
uint32_t urgc = so->so_urgc; /* Amount of room left in buff */
int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
if (len > urgc) {
len = urgc;
......@@ -357,6 +360,7 @@ int sosendoob(struct socket *so)
memcpy(buff, sb->sb_rptr, len);
urgc -= len;
if (urgc) {
/* We still have some room for the rest */
n = sb->sb_wptr - sb->sb_data;
if (n > urgc) {
n = urgc;
......@@ -493,12 +497,67 @@ void sorecvfrom(struct socket *so)
struct sockaddr_storage addr;
struct sockaddr_storage saddr, daddr;
socklen_t addrlen = sizeof(struct sockaddr_storage);
char buff[256];
#ifdef __linux__
ssize_t size;
struct msghdr msg;
struct iovec iov;
char control[1024];
/* First look for errors */
memset(&msg, 0, sizeof(msg));
msg.msg_name = &saddr;
msg.msg_namelen = sizeof(saddr);
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
iov.iov_base = buff;
iov.iov_len = sizeof(buff);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
size = recvmsg(so->s, &msg, MSG_ERRQUEUE);
if (size >= 0) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_RECVERR) {
struct sock_extended_err *ee =
(struct sock_extended_err *) CMSG_DATA(cmsg);
if (ee->ee_origin == SO_EE_ORIGIN_ICMP) {
/* Got an ICMP error, forward it */
struct sockaddr_in *sin;
sin = (struct sockaddr_in *) SO_EE_OFFENDER(ee);
icmp_forward_error(so->so_m, ee->ee_type, ee->ee_code,
0, NULL, &sin->sin_addr);
}
}
else if (cmsg->cmsg_level == IPPROTO_IPV6 &&
cmsg->cmsg_type == IPV6_RECVERR) {
struct sock_extended_err *ee =
(struct sock_extended_err *) CMSG_DATA(cmsg);
if (ee->ee_origin == SO_EE_ORIGIN_ICMP6) {
/* Got an ICMPv6 error, forward it */
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *) SO_EE_OFFENDER(ee);
icmp6_forward_error(so->so_m, ee->ee_type, ee->ee_code,
&sin6->sin6_addr);
}
}
}
return;
}
#endif
DEBUG_CALL("sorecvfrom");
DEBUG_ARG("so = %p", so);
if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */
char buff[256];
int len;
len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen);
......@@ -533,9 +592,6 @@ void sorecvfrom(struct socket *so)
DEBUG_MISC(" ioctlsocket errno = %d-%s\n", errno, strerror(errno));
return;
}
if (n == 0) {
return;
}
m = m_get(so->slirp);
if (!m) {
......
......@@ -88,8 +88,8 @@ struct tcpiphdr {
/* This is the difference between the size of a tcpiphdr structure, and the
* size of actual ip+tcp headers, rounded up since we need to align data. */
#define TCPIPHDR_DELTA \
(MAX(0, (sizeof(struct tcpiphdr) - sizeof(struct ip) - \
sizeof(struct tcphdr) + 3) & \
(MAX(0, ((int) sizeof(struct tcpiphdr) - (int) sizeof(struct ip) - \
(int) sizeof(struct tcphdr) + 3) & \
~3))
/*
......
......@@ -74,6 +74,7 @@ void udp_input(register struct mbuf *m, int iphlen)
struct socket *so;
struct sockaddr_storage lhost;
struct sockaddr_in *lhost4;
int ttl;
DEBUG_CALL("udp_input");
DEBUG_ARG("m = %p", m);
......@@ -202,6 +203,20 @@ void udp_input(register struct mbuf *m, int iphlen)
m->m_len -= iphlen;
m->m_data += iphlen;
/*
* Check for TTL
*/
ttl = save_ip.ip_ttl-1;
if (ttl <= 0) {
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
DEBUG_MISC("udp ttl exceeded");
icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, NULL);
goto bad;
}
setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
/*
* Now we sendto() the packet.
*/
......@@ -288,6 +303,23 @@ int udp_attach(struct socket *so, unsigned short af)
so->s = -1;
return -1;
}
#ifdef __linux__
{
int opt = 1;
switch (af) {
case AF_INET:
setsockopt(so->s, IPPROTO_IP, IP_RECVERR, &opt, sizeof(opt));
break;
case AF_INET6:
setsockopt(so->s, IPPROTO_IPV6, IPV6_RECVERR, &opt, sizeof(opt));
break;
default:
g_assert_not_reached();
}
}
#endif
so->so_expire = curtime + SO_EXPIRE;
insque(so, &so->slirp->udb);
}
......
......@@ -17,6 +17,7 @@ void udp6_input(struct mbuf *m)
int len;
struct socket *so;
struct sockaddr_in6 lhost;
int hop_limit;
DEBUG_CALL("udp6_input");
DEBUG_ARG("m = %p", m);
......@@ -110,6 +111,20 @@ void udp6_input(struct mbuf *m)
m->m_len -= iphlen;
m->m_data += iphlen;
/*
* Check for TTL
*/
hop_limit = save_ip.ip_hl-1;
if (hop_limit <= 0) {
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
DEBUG_MISC("udp ttl exceeded");
icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
goto bad;
}
setsockopt(so->s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, sizeof(hop_limit));
/*
* Now we sendto() the packet.
*/
......
......@@ -365,6 +365,7 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str)
*q = '\0';
}
G_GNUC_PRINTF(3, 0)
static int slirp_vsnprintf(char *str, size_t size,
const char *format, va_list args)
{
......