Codebase list slirp4netns / upstream/latest
New upstream version 1.0.1 Reinhard Tartler 3 years ago
90 changed file(s) with 2242 addition(s) and 16951 deletion(s). Raw diff Collapse all Expand all
0 # https://clang.llvm.org/docs/ClangFormat.html
1 # https://clang.llvm.org/docs/ClangFormatStyleOptions.html
2 ---
3 Language: Cpp
4 AlignAfterOpenBracket: Align
5 AlignConsecutiveAssignments: false # although we like it, it creates churn
6 AlignConsecutiveDeclarations: false
7 AlignEscapedNewlinesLeft: true
8 AlignOperands: true
9 AlignTrailingComments: false # churn
10 AllowAllParametersOfDeclarationOnNextLine: true
11 AllowShortBlocksOnASingleLine: false
12 AllowShortCaseLabelsOnASingleLine: false
13 AllowShortFunctionsOnASingleLine: None
14 AllowShortIfStatementsOnASingleLine: false
15 AllowShortLoopsOnASingleLine: false
16 AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
17 AlwaysBreakBeforeMultilineStrings: false
18 BinPackArguments: true
19 BinPackParameters: true
20 BraceWrapping:
21 AfterControlStatement: false
22 AfterEnum: false
23 AfterFunction: true
24 AfterStruct: false
25 AfterUnion: false
26 BeforeElse: false
27 IndentBraces: false
28 BreakBeforeBinaryOperators: None
29 BreakBeforeBraces: Custom
30 BreakBeforeTernaryOperators: false
31 BreakStringLiterals: true
32 ColumnLimit: 80
33 ContinuationIndentWidth: 4
34 Cpp11BracedListStyle: false
35 DerivePointerAlignment: false
36 DisableFormat: false
37 IndentCaseLabels: false
38 IndentWidth: 4
39 IndentWrappedFunctionNames: false
40 KeepEmptyLinesAtTheStartOfBlocks: false
41 MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
42 MacroBlockEnd: '.*_END$'
43 MaxEmptyLinesToKeep: 2
44 PointerAlignment: Right
45 ReflowComments: true
46 SortIncludes: false
47 SpaceAfterCStyleCast: false
48 SpaceBeforeAssignmentOperators: true
49 SpaceBeforeParens: ControlStatements
50 SpaceInEmptyParentheses: false
51 SpacesBeforeTrailingComments: 1
52 SpacesInContainerLiterals: true
53 SpacesInParentheses: false
54 SpacesInSquareBrackets: false
55 Standard: Auto
56 UseTab: Never
57 ...
0 name: Main
1 on: [push, pull_request]
2 jobs:
3 test-main:
4 runs-on: ubuntu-latest
5 strategy:
6 matrix:
7 libslirp_commit: [master, v4.3.0, v4.2.0, v4.1.0]
8 steps:
9 - uses: actions/checkout@v1
10 - run: docker build -t slirp4netns-tests --build-arg LIBSLIRP_COMMIT -f Dockerfile.tests .
11 env:
12 LIBSLIRP_COMMIT: ${{ matrix.libslirp_commit }}
13 - run: docker run --rm --privileged slirp4netns-tests
14 test-build:
15 runs-on: ubuntu-latest
16 steps:
17 - uses: actions/checkout@v1
18 - run: DOCKER_BUILDKIT=1 docker build -f Dockerfile.buildtests .
19 artifact:
20 runs-on: ubuntu-latest
21 steps:
22 - uses: actions/checkout@v1
23 - run: DOCKER_BUILDKIT=1 docker build -o /tmp/artifact --target artifact -f Dockerfile.buildtests .
24 - run: (cd /tmp/artifact; sha256sum *)
25 - uses: actions/upload-artifact@v1
26 with:
27 name: slirp4netns-x86_64
28 path: /tmp/artifact/slirp4netns
0 name: Release
1 on:
2 push:
3 tags:
4 - 'v*'
5
6 jobs:
7 release:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v1
11 - run: DOCKER_BUILDKIT=1 docker build -o /tmp/artifact --target artifact -f Dockerfile.buildtests .
12 - run: (cd /tmp/artifact; sha256sum *)
13 - uses: actions/create-release@v1
14 id: create_release
15 env:
16 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17 with:
18 tag_name: ${{ github.ref }}
19 release_name: ${{ github.ref }}
20 draft: true
21 - uses: actions/upload-release-asset@v1.0.1
22 env:
23 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 with:
25 upload_url: ${{ steps.create_release.outputs.upload_url }}
26 asset_path: /tmp/artifact/slirp4netns
27 asset_name: slirp4netns-x86_64
28 asset_content_type: application/octet-stream
+0
-10
.travis.yml less more
0 dist: trusty
1 sudo: required
2
3 services:
4 - docker
5
6 script:
7 - docker build -t slirp4netns-tests -f Dockerfile.tests .
8 - docker run --security-opt seccomp="unconfined" -ti --rm -v /dev:/dev slirp4netns-tests
9 - docker build -q -f Dockerfile.buildtests .
0 FROM alpine:3.8 AS buildtest-alpine38-static
1 RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static
0 ARG LIBSLIRP_COMMIT=v4.3.0
1
2 # Alpine
3 FROM alpine:3 AS buildtest-alpine3-static
4 RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static libcap-static libcap-dev libseccomp-dev git meson
5 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
6 WORKDIR /libslirp
7 ARG LIBSLIRP_COMMIT
8 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both build && ninja -C build install
29 COPY . /src
310 WORKDIR /src
411 RUN ./autogen.sh && ./configure LDFLAGS="-static" && make && cp -f slirp4netns /
512
13 # Ubuntu
614 FROM ubuntu:18.04 AS buildtest-ubuntu1804-common
7 RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev
15 RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
16 RUN pip3 install meson
17 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
18 WORKDIR /libslirp
19 ARG LIBSLIRP_COMMIT
20 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup build && ninja -C build install
821 COPY . /src
922 WORKDIR /src
1023 RUN ./autogen.sh
1225 FROM buildtest-ubuntu1804-common AS buildtest-ubuntu1804-dynamic
1326 RUN ./configure && make && cp -f slirp4netns /
1427
15 FROM buildtest-ubuntu1804-common AS buildtest-ubuntu1804-static
28 # CentOS
29 FROM centos:7 AS buildtest-centos7-common
30 RUN yum install -y epel-release
31 RUN yum install -y autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel ninja-build python3-pip
32 RUN pip3 install meson
33 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
34 WORKDIR /libslirp
35 ARG LIBSLIRP_COMMIT
36 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both --prefix=/usr build && ninja-build -C build install
37 COPY . /src
38 WORKDIR /src
39 RUN ./autogen.sh
40
41 FROM buildtest-centos7-common AS buildtest-centos7-dynamic
42 RUN ./configure && make && cp -f slirp4netns /
43
44 FROM buildtest-centos7-common AS buildtest-centos7-static
45 RUN yum install -y glibc-static glib2-static
46 RUN yum-config-manager --add-repo=https://buildlogs.centos.org/centos/7/virt/x86_64/container && \
47 yum install --nogpgcheck -y libseccomp-static
1648 RUN ./configure LDFLAGS="-static" && make && cp -f slirp4netns /
1749
50 # openSUSE (dynamic only)
51 FROM opensuse/leap:15 AS buildtest-opensuse15-common
52 RUN zypper install -y --no-recommends autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel ninja python3-pip
53 RUN pip3 install meson
54 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
55 WORKDIR /libslirp
56 ARG LIBSLIRP_COMMIT
57 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both build && ninja -C build install
58 COPY . /src
59 WORKDIR /src
60 RUN ./autogen.sh
61
62 FROM buildtest-opensuse15-common AS buildtest-opensuse15-dynamic
63 RUN ./configure && make && cp -f slirp4netns /
64
65 # artifact for GitHub actions
66 FROM scratch AS artifact
67 COPY --from=buildtest-centos7-static /slirp4netns /slirp4netns
68
1869 FROM scratch AS buildtest-final-stage
19 COPY --from=buildtest-alpine38-static /slirp4netns /buildtest-alpine38-static
70 COPY --from=buildtest-alpine3-static /slirp4netns /buildtest-alpine3-static
2071 COPY --from=buildtest-ubuntu1804-dynamic /slirp4netns /buildtest-ubuntu1804-dynamic
21 COPY --from=buildtest-ubuntu1804-static /slirp4netns /buildtest-ubuntu1804-static
72 COPY --from=buildtest-centos7-dynamic /slirp4netns /buildtest-centos7-dynamic
73 COPY --from=buildtest-centos7-static /slirp4netns /buildtest-centos7-static
74 COPY --from=buildtest-opensuse15-dynamic /slirp4netns /buildtest-opensuse15-dynamic
0 FROM ubuntu AS build
1 RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev
0 ARG LIBSLIRP_COMMIT=v4.3.0
1
2 FROM ubuntu:18.04 AS build
3 RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
4 RUN pip3 install meson
5 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
6 WORKDIR /libslirp
7 ARG LIBSLIRP_COMMIT
8 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup build && ninja -C build install
29 COPY . /slirp4netns
310 WORKDIR /slirp4netns
411 RUN chown -R 1000:1000 /slirp4netns
714
815 FROM build AS test
916 USER 0
10 RUN apt update && apt install -y git indent libtool iproute2 clang clang-tidy iputils-ping iperf3 nmap jq
17 RUN apt update && apt install -y git libtool iproute2 clang clang-format clang-tidy iputils-ping iperf3 nmap jq
1118 USER 1000:1000
1219 CMD ["make", "ci"]
11
22 [Org]
33
4 # Approvers (aka Core Maintainers) approve pull requests.
4 # Approvers (aka Core Maintainers) approve pull requests and ship releases.
55 # GitHub Team: rootless-containers/slirp4netns-approvers
6 #
7 # An approver may approve PRs and ship releases without waiting for LGTMs from other approvers.
8 # However, the approver should try to get LGTMs from other approvers for significant changes.
9 #
10 # Release guide (since v0.4.3):
11 # 1. Bump up the version string to `vX.Y.Z` (or `vX.Y.Z-beta.W`) in `configure.ac`.
12 # 2. `git commit -a -s -m vX.Y.Z`
13 # 3. Bump up the version string to `vX.Y.Z+dev` (or `vX.Y.Z-beta.W`+dev) in `configure.ac`.
14 # 4. `git commit -a -s -m vX.Y.Z+dev`
15 # 5. Open a PR and merge it.
16 # 6. Create a tag `v.X.Y.Z` for the `vX.Y.Z` commit, and push the tag to the upstream: `git push upstream vX.Y.Z`
17 # 7. GitHub Actions automatically ships a draft release with a statically compiled binary: https://github.com/rootless-containers/slirp4netns/releases
18 # If it fails, check the GitHub Actions log: https://github.com/rootless-containers/slirp4netns/actions?query=workflow%3ARelease
19 # 8. Add release notes to the draft release and ship the release.
620 [Org.Approvers]
721 people = [
822 "akihirosuda",
7286 [people]
7387 [people.akihirosuda]
7488 Name = "Akihiro Suda"
75 Email = "suda.akihiro@lab.ntt.co.jp"
89 Email = "akihiro.suda.cz@hco.ntt.co.jp"
7690 GitHub = "AkihiroSuda"
7791
7892 [people.barthalion]
00 bin_PROGRAMS = slirp4netns
11
2 AM_CFLAGS = @GLIB_CFLAGS@
2 AM_CFLAGS = @GLIB_CFLAGS@ @SLIRP_CFLAGS@ @LIBCAP_CFLAGS@ @LIBSECCOMP_CFLAGS@
33
4 noinst_LIBRARIES = libslirp.a libparson.a
4 noinst_LIBRARIES = libparson.a
55
66 AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)"
77 TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh
1313 tests/common.sh \
1414 slirp4netns.h \
1515 api.h \
16 vendor/libslirp/COPYRIGHT \
17 vendor/libslirp/README.md \
18 vendor/libslirp/src/bootp.h \
19 vendor/libslirp/src/debug.h \
20 vendor/libslirp/src/dhcpv6.h \
21 vendor/libslirp/src/if.h \
22 vendor/libslirp/src/ip6.h \
23 vendor/libslirp/src/ip6_icmp.h \
24 vendor/libslirp/src/ip.h \
25 vendor/libslirp/src/ip_icmp.h \
26 vendor/libslirp/src/libslirp.h \
27 vendor/libslirp/src/libslirp-version.h \
28 vendor/libslirp/src/main.h \
29 vendor/libslirp/src/mbuf.h \
30 vendor/libslirp/src/misc.h \
31 vendor/libslirp/src/ncsi-pkt.h \
32 vendor/libslirp/src/sbuf.h \
33 vendor/libslirp/src/slirp.h \
34 vendor/libslirp/src/socket.h \
35 vendor/libslirp/src/stream.h \
36 vendor/libslirp/src/tftp.h \
37 vendor/libslirp/src/tcp.h \
38 vendor/libslirp/src/tcpip.h \
39 vendor/libslirp/src/tcp_timer.h \
40 vendor/libslirp/src/tcp_var.h \
41 vendor/libslirp/src/udp.h \
42 vendor/libslirp/src/util.h \
43 vendor/libslirp/src/vmstate.h \
16 sandbox.h \
17 seccompfilter.h \
18 tests/slirp4netns-no-unmount.sh \
4419 vendor/parson/LICENSE \
4520 vendor/parson/README.md \
4621 vendor/parson/parson.h
4722
48 libslirp_a_SOURCES = \
49 vendor/libslirp/src/arp_table.c \
50 vendor/libslirp/src/bootp.c \
51 vendor/libslirp/src/cksum.c \
52 vendor/libslirp/src/dhcpv6.c \
53 vendor/libslirp/src/dnssearch.c \
54 vendor/libslirp/src/if.c \
55 vendor/libslirp/src/ip6_icmp.c \
56 vendor/libslirp/src/ip6_input.c \
57 vendor/libslirp/src/ip6_output.c \
58 vendor/libslirp/src/ip_icmp.c \
59 vendor/libslirp/src/ip_input.c \
60 vendor/libslirp/src/ip_output.c \
61 vendor/libslirp/src/mbuf.c \
62 vendor/libslirp/src/misc.c \
63 vendor/libslirp/src/ncsi.c \
64 vendor/libslirp/src/ndp_table.c \
65 vendor/libslirp/src/sbuf.c \
66 vendor/libslirp/src/slirp.c \
67 vendor/libslirp/src/socket.c \
68 vendor/libslirp/src/state.c \
69 vendor/libslirp/src/stream.c \
70 vendor/libslirp/src/tcp_input.c \
71 vendor/libslirp/src/tcp_output.c \
72 vendor/libslirp/src/tcp_subr.c \
73 vendor/libslirp/src/tcp_timer.c \
74 vendor/libslirp/src/tftp.c \
75 vendor/libslirp/src/udp6.c \
76 vendor/libslirp/src/udp.c \
77 vendor/libslirp/src/util.c \
78 vendor/libslirp/src/version.c \
79 vendor/libslirp/src/vmstate.c
80
8123 # define specific commit if git available or it was replaced during git-archive creation
82 COMMIT := $(shell V=5e1639783df9bd7abbc46abc084a53c1093342d8 ; \
24 COMMIT := $(shell V=6a7b16babc95b6a3056b33fb45b74a6f62262dd4 ; \
8325 expr match "$$V" ormat: >/dev/null \
8426 && (cd "$$abs_srcdir" && [ -d .git ] && git describe --always --abbrev=0 --dirty --exclude=\* || echo unknown) \
8527 || echo "$$V" )
8628 DEFINE_COMMIT = -DCOMMIT="\"$(COMMIT)\""
8729
8830 slirp4netns_CFLAGS = $(AM_CFLAGS) $(DEFINE_COMMIT)
89 libslirp_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/vendor/libslirp/src
9031 libparson_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/vendor/parson
9132 libparson_a_SOURCES = vendor/parson/parson.c
9233
93 slirp4netns_SOURCES = main.c slirp4netns.c api.c
94 slirp4netns_LDADD = libslirp.a libparson.a @GLIB_LIBS@ -lpthread
34 slirp4netns_SOURCES = main.c slirp4netns.c api.c sandbox.c seccompfilter.c
35 slirp4netns_LDADD = libparson.a @GLIB_LIBS@ @SLIRP_LIBS@ @LIBSECCOMP_LIBS@ -lpthread
9536 man1_MANS = slirp4netns.1
9637
9738 generate-man:
9940
10041 CLANGTIDY = clang-tidy -warnings-as-errors='*'
10142
43 CLANGFORMAT = clang-format
44
10245 lint:
10346 $(CLANGTIDY) $(slirp4netns_SOURCES) -- $(AM_CFLAGS)
10447
10548 lint-full:
106 $(CLANGTIDY) $(slirp4netns_SOURCES) $(libslirp_a_SOURCES) $(libparson_a_SOURCES) -- $(AM_CFLAGS)
49 $(CLANGTIDY) $(slirp4netns_SOURCES) $(libparson_a_SOURCES) -- $(AM_CFLAGS)
10750
10851 indent:
109 # indent(1): "You must use the ‘-T’ option to tell indent the name of all the typenames in your program that are defined by typedef."
110 indent -linux -l120 \
111 -T ssize_t -T pid_t \
112 -T GArray -T GList -T GSList -T GPollFD -T gpointer -T gconstpointer \
113 -T Slirp -T SlirpCb -T SlirpConfig -T SlirpTimerCb \
114 -T JSON_Object -T JSON_Value \
115 -T regex_t -T regmatch_t \
116 $(slirp4netns_SOURCES)
117 $(RM) *.c~
118
52 $(CLANGFORMAT) -i $(slirp4netns_SOURCES)
11953
12054 benchmark:
12155 benchmarks/benchmark-iperf3.sh
12357
12458 ci:
12559 $(MAKE) indent
126 test -z "$(git diff)"
60 git diff --exit-code
12761 # TODO: make sure ./vendor is synced with ./vendor.sh
128 # (hard to verify during `make`, because sync.sh removes ./vendor/libslirp/src/.deps)
12962 $(MAKE) lint
13063 $(MAKE) -j $(shell nproc) distcheck || ( find . -name test-suite.log | xargs cat; exit 1 )
13164 PATH=$(shell pwd):$$PATH $(MAKE) benchmark MTU=1500
00 # slirp4netns: User-mode networking for unprivileged network namespaces
11
22 slirp4netns provides user-mode networking ("slirp") for unprivileged network namespaces.
3
4 Latest stable release: [v0.3.X](https://github.com/rootless-containers/slirp4netns/releases)
53
64 ## Motivation
75
1210
1311 ## Projects using slirp4netns
1412
13 Kubernetes distributions:
1514 * [Usernetes](https://github.com/rootless-containers/usernetes) (via RootlessKit)
15 * [k3s](https://k3s.io) (via RootlessKit)
16
17 Container engines:
1618 * [Podman](https://github.com/containers/libpod)
1719 * [Buildah](https://github.com/containers/buildah)
1820 * [ctnr](https://github.com/mgoltzsche/ctnr) (via slirp-cni-plugin)
1921 * [Docker & Moby](https://get.docker.com/rootless) (optionally, via RootlessKit)
2022
23 Tools:
2124 * [RootlessKit](https://github.com/rootless-containers/rootlesskit)
2225 * [become-root](https://github.com/giuseppe/become-root)
2326 * [slirp-cni-plugin](https://github.com/mgoltzsche/slirp-cni-plugin)
2427
28 ## Maintenance policy
29
30 Version | Status
31 -------------------------------|------------------------------------------------------------------------
32 v1.0.x | :white_check_mark: Active
33 v0.4.x | :white_check_mark: Active (EOL: Sep 30, 2020)
34 v0.3.x | :warning: End of Life (Mar 31, 2020)
35 v0.2.x | :warning: End of Life (Aug 30, 2019)
36 Early versions prior to v0.2.x | :warning: End of Life (Jan 5, 2019)
37
38 See https://github.com/rootless-containers/slirp4netns/releases for the releases.
39
40 See https://github.com/rootless-containers/slirp4netns/security/advisories for the past security advisories.
41
2542 ## Quick start
2643
2744 ### Install from source
2845
29 Build dependency: `glib2-devel` (`libglib2.0-dev`)
46 Build dependencies:
47 * `glib2-devel` (`libglib2.0-dev`)
48 * `libslirp-devel` >= 4.1 (`libslirp-dev`)
49 * `libcap-devel` (`libcap-dev`)
50 * `libseccomp-devel` (`libseccomp-dev`)
51
52 Install steps:
3053
3154 ```console
3255 $ ./autogen.sh
4467
4568 ```console
4669 $ sudo dnf install slirp4netns
70 ```
71
72 #### RHEL/CentOS 7.7
73
74 ```console
75 $ sudo yum install slirp4netns
4776 ```
4877
4978 #### [RHEL/CentOS 7.6](https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/)
170199 The latest revision of slirp4netns is regularly benchmarked (`make benchmark`) on Travis: https://travis-ci.org/rootless-containers/slirp4netns
171200
172201 ## Acknowledgement
173
174202 See [`vendor/README.md`](./vendor/README.md).
203
204 ## License
205 [GPL-2.0-or-later](COPYING)
+303
-271
api.c less more
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
01 #define _GNU_SOURCE
12 #include <stdio.h>
23 #include <stdlib.h>
34 #include <unistd.h>
45 #include <sys/un.h>
56 #include <glib.h>
7 #include <libslirp.h>
68 #include "vendor/parson/parson.h"
7 #include "vendor/libslirp/src/libslirp.h"
89 #include "api.h"
910 #include "slirp4netns.h"
1011
1112 int api_bindlisten(const char *api_socket)
1213 {
13 int fd;
14 struct sockaddr_un addr;
15 unlink(api_socket); /* avoid EADDRINUSE */
16 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
17 perror("api_bindlisten: socket");
18 return -1;
19 }
20 memset(&addr, 0, sizeof(addr));
21 addr.sun_family = AF_UNIX;
22 strncpy(addr.sun_path, api_socket, sizeof(addr.sun_path) - 1);
23 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
24 perror("api_bindlisten: bind");
25 return -1;
26 }
27 if (listen(fd, 0) < 0) {
28 perror("api_bindlisten: listen");
29 return -1;
30 }
31 return fd;
14 int fd;
15 struct sockaddr_un addr;
16 unlink(api_socket); /* avoid EADDRINUSE */
17 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
18 perror("api_bindlisten: socket");
19 return -1;
20 }
21 memset(&addr, 0, sizeof(addr));
22 addr.sun_family = AF_UNIX;
23 if (strlen(api_socket) >= sizeof(addr.sun_path)) {
24 fprintf(stderr, "the specified API socket path is too long (>= %lu)\n",
25 sizeof(addr.sun_path));
26 return -1;
27 }
28 strncpy(addr.sun_path, api_socket, sizeof(addr.sun_path) - 1);
29 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
30 perror("api_bindlisten: bind");
31 return -1;
32 }
33 if (listen(fd, 0) < 0) {
34 perror("api_bindlisten: listen");
35 return -1;
36 }
37 return fd;
3238 }
3339
3440 struct api_hostfwd {
35 int id;
36 int is_udp;
37 struct in_addr host_addr;
38 int host_port;
39 struct in_addr guest_addr;
40 int guest_port;
41 int id;
42 int is_udp;
43 struct in_addr host_addr;
44 int host_port;
45 struct in_addr guest_addr;
46 int guest_port;
4147 };
4248
4349 struct api_ctx {
44 uint8_t *buf;
45 size_t buflen;
46 GList *hostfwds;
47 int hostfwds_nextid;
48 struct slirp4netns_config *cfg;
50 uint8_t *buf;
51 size_t buflen;
52 GList *hostfwds;
53 int hostfwds_nextid;
54 struct slirp4netns_config *cfg;
4955 };
5056
5157 struct api_ctx *api_ctx_alloc(struct slirp4netns_config *cfg)
5258 {
53 struct api_ctx *ctx = (struct api_ctx *)g_malloc0(sizeof(*ctx));
54 if (ctx == NULL) {
55 return NULL;
56 }
57 ctx->buflen = 4096;
58 ctx->buf = malloc(ctx->buflen); /* FIXME: realloc */
59 if (ctx->buf == NULL) {
60 free(ctx);
61 return NULL;
62 }
63 ctx->cfg = cfg;
64 ctx->hostfwds = NULL;
65 ctx->hostfwds_nextid = 1;
66 return ctx;
59 struct api_ctx *ctx = (struct api_ctx *)g_malloc0(sizeof(*ctx));
60 if (ctx == NULL) {
61 return NULL;
62 }
63 ctx->buflen = 4096;
64 ctx->buf = malloc(ctx->buflen); /* FIXME: realloc */
65 if (ctx->buf == NULL) {
66 free(ctx);
67 return NULL;
68 }
69 ctx->cfg = cfg;
70 ctx->hostfwds = NULL;
71 ctx->hostfwds_nextid = 1;
72 return ctx;
6773 }
6874
6975 void api_ctx_free(struct api_ctx *ctx)
7076 {
71 if (ctx != NULL) {
72 if (ctx->buf != NULL) {
73 free(ctx->buf);
74 }
75 g_list_free_full(ctx->hostfwds, g_free);
76 free(ctx);
77 }
77 if (ctx != NULL) {
78 if (ctx->buf != NULL) {
79 free(ctx->buf);
80 }
81 g_list_free_full(ctx->hostfwds, g_free);
82 free(ctx);
83 }
7884 }
7985
8086 /*
8187 Handler for add_hostfwd.
82 e.g. {"execute": "add_hostfwd", "arguments": {"proto": "tcp", "host_addr": "0.0.0.0", "host_port": 8080, "guest_addr": "10.0.2.100", "guest_port": 80}}
83 This function returns the return value of write(2), not the return value of slirp_add_hostfwd().
88 e.g. {"execute": "add_hostfwd", "arguments": {"proto": "tcp", "host_addr":
89 "0.0.0.0", "host_port": 8080, "guest_addr": "10.0.2.100", "guest_port": 80}}
90 This function returns the return value of write(2), not the return value of
91 slirp_add_hostfwd().
8492 */
85 static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, JSON_Object *jo)
86 {
87 int wrc = 0, slirprc = 0;
88 int id = -1;
89 char idbuf[64];
90 const char *proto_s = json_object_dotget_string(jo, "arguments.proto");
91 const char *host_addr_s = json_object_dotget_string(jo, "arguments.host_addr");
92 const char *guest_addr_s = json_object_dotget_string(jo, "arguments.guest_addr");
93 struct api_hostfwd *fwd = g_malloc0(sizeof(*fwd));
94 if (fwd == NULL) {
95 perror("fatal: malloc");
96 exit(EXIT_FAILURE);
97 }
98 fwd->is_udp = -1; /* TODO: support SCTP */
99 if (strcmp(proto_s, "udp") == 0) {
100 fwd->is_udp = 1;
101 } else if (strcmp(proto_s, "tcp") == 0) {
102 fwd->is_udp = 0;
103 }
104 if (fwd->is_udp == -1) {
105 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: bad arguments.proto\"}}";
106 wrc = write(fd, err, strlen(err));
107 free(fwd);
108 goto finish;
109 }
110 if (host_addr_s == NULL || host_addr_s[0] == '\0') {
111 host_addr_s = "0.0.0.0";
112 }
113 if (inet_pton(AF_INET, host_addr_s, &fwd->host_addr) != 1) {
114 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: bad arguments.host_addr\"}}";
115 wrc = write(fd, err, strlen(err));
116 free(fwd);
117 goto finish;
118 }
119 fwd->host_port = (int)json_object_dotget_number(jo, "arguments.host_port");
120 if (fwd->host_port == 0) {
121 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: bad arguments.host_port\"}}";
122 wrc = write(fd, err, strlen(err));
123 free(fwd);
124 goto finish;
125 }
126
127 if (guest_addr_s == NULL || guest_addr_s[0] == '\0') {
128 fwd->guest_addr = ctx->cfg->recommended_vguest;
129 } else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest_addr) != 1) {
130 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: bad arguments.guest_addr\"}}";
131 wrc = write(fd, err, strlen(err));
132 free(fwd);
133 goto finish;
134 }
135 fwd->guest_port = (int)json_object_dotget_number(jo, "arguments.guest_port");
136 if (fwd->guest_port == 0) {
137 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: bad arguments.guest_port\"}}";
138 wrc = write(fd, err, strlen(err));
139 free(fwd);
140 goto finish;
141 }
142 if ((slirprc =
143 slirp_add_hostfwd(slirp, fwd->is_udp, fwd->host_addr, fwd->host_port, fwd->guest_addr,
144 fwd->guest_port)) < 0) {
145 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: slirp_add_hostfwd failed\"}}";
146 wrc = write(fd, err, strlen(err));
147 free(fwd);
148 goto finish;
149 }
150 fwd->id = ctx->hostfwds_nextid;
151 ctx->hostfwds_nextid++;
152 ctx->hostfwds = g_list_append(ctx->hostfwds, fwd);
153 if (snprintf(idbuf, sizeof(idbuf), "{\"return\":{\"id\":%d}}", fwd->id) > sizeof(idbuf)) {
154 fprintf(stderr, "fatal: unexpected id=%d\n", fwd->id);
155 exit(EXIT_FAILURE);
156 }
157 wrc = write(fd, idbuf, strlen(idbuf));
158 finish:
159 return wrc;
160 }
161
162 static void api_handle_req_list_hostfwd_foreach(gpointer data, gpointer user_data)
163 {
164 struct api_hostfwd *fwd = data;
165 JSON_Array *entries_array = (JSON_Array *) user_data;
166 JSON_Value *entry_value = json_value_init_object();
167 JSON_Object *entry_object = json_value_get_object(entry_value);
168 char host_addr[INET_ADDRSTRLEN], guest_addr[INET_ADDRSTRLEN];
169 if (inet_ntop(AF_INET, &fwd->host_addr, host_addr, sizeof(host_addr)) == NULL) {
170 perror("fatal: inet_ntop");
171 exit(EXIT_FAILURE);
172 }
173 if (inet_ntop(AF_INET, &fwd->guest_addr, guest_addr, sizeof(guest_addr)) == NULL) {
174 perror("fatal: inet_ntop");
175 exit(EXIT_FAILURE);
176 }
177 json_object_set_number(entry_object, "id", fwd->id);
178 json_object_set_string(entry_object, "proto", fwd->is_udp ? "udp" : "tcp");
179 json_object_set_string(entry_object, "host_addr", host_addr);
180 json_object_set_number(entry_object, "host_port", fwd->host_port);
181 json_object_set_string(entry_object, "guest_addr", guest_addr);
182 json_object_set_number(entry_object, "guest_port", fwd->guest_port);
183 /* json_array_append_value does not copy passed value */
184 if (json_array_append_value(entries_array, entry_value) != JSONSuccess) {
185 fprintf(stderr, "fatal: json_array_append_value\n");
186 exit(EXIT_FAILURE);
187 }
93 static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx,
94 JSON_Object *jo)
95 {
96 int wrc = 0, slirprc = 0;
97 char idbuf[64];
98 const char *proto_s = json_object_dotget_string(jo, "arguments.proto");
99 const char *host_addr_s =
100 json_object_dotget_string(jo, "arguments.host_addr");
101 const char *guest_addr_s =
102 json_object_dotget_string(jo, "arguments.guest_addr");
103 struct api_hostfwd *fwd = g_malloc0(sizeof(*fwd));
104 if (fwd == NULL) {
105 perror("fatal: malloc");
106 exit(EXIT_FAILURE);
107 }
108 fwd->is_udp = -1; /* TODO: support SCTP */
109 if (strcmp(proto_s, "udp") == 0) {
110 fwd->is_udp = 1;
111 } else if (strcmp(proto_s, "tcp") == 0) {
112 fwd->is_udp = 0;
113 }
114 if (fwd->is_udp == -1) {
115 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
116 "bad arguments.proto\"}}";
117 wrc = write(fd, err, strlen(err));
118 free(fwd);
119 goto finish;
120 }
121 if (host_addr_s == NULL || host_addr_s[0] == '\0') {
122 host_addr_s = "0.0.0.0";
123 }
124 if (inet_pton(AF_INET, host_addr_s, &fwd->host_addr) != 1) {
125 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
126 "bad arguments.host_addr\"}}";
127 wrc = write(fd, err, strlen(err));
128 free(fwd);
129 goto finish;
130 }
131 fwd->host_port = (int)json_object_dotget_number(jo, "arguments.host_port");
132 if (fwd->host_port == 0) {
133 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
134 "bad arguments.host_port\"}}";
135 wrc = write(fd, err, strlen(err));
136 free(fwd);
137 goto finish;
138 }
139
140 if (guest_addr_s == NULL || guest_addr_s[0] == '\0') {
141 fwd->guest_addr = ctx->cfg->recommended_vguest;
142 } else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest_addr) != 1) {
143 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
144 "bad arguments.guest_addr\"}}";
145 wrc = write(fd, err, strlen(err));
146 free(fwd);
147 goto finish;
148 }
149 fwd->guest_port =
150 (int)json_object_dotget_number(jo, "arguments.guest_port");
151 if (fwd->guest_port == 0) {
152 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
153 "bad arguments.guest_port\"}}";
154 wrc = write(fd, err, strlen(err));
155 free(fwd);
156 goto finish;
157 }
158 if ((slirprc = slirp_add_hostfwd(slirp, fwd->is_udp, fwd->host_addr,
159 fwd->host_port, fwd->guest_addr,
160 fwd->guest_port)) < 0) {
161 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
162 "slirp_add_hostfwd failed\"}}";
163 wrc = write(fd, err, strlen(err));
164 free(fwd);
165 goto finish;
166 }
167 fwd->id = ctx->hostfwds_nextid;
168 ctx->hostfwds_nextid++;
169 ctx->hostfwds = g_list_append(ctx->hostfwds, fwd);
170 if (snprintf(idbuf, sizeof(idbuf), "{\"return\":{\"id\":%d}}", fwd->id) >
171 sizeof(idbuf)) {
172 fprintf(stderr, "fatal: unexpected id=%d\n", fwd->id);
173 exit(EXIT_FAILURE);
174 }
175 wrc = write(fd, idbuf, strlen(idbuf));
176 finish:
177 return wrc;
178 }
179
180 static void api_handle_req_list_hostfwd_foreach(gpointer data,
181 gpointer user_data)
182 {
183 struct api_hostfwd *fwd = data;
184 JSON_Array *entries_array = (JSON_Array *)user_data;
185 JSON_Value *entry_value = json_value_init_object();
186 JSON_Object *entry_object = json_value_get_object(entry_value);
187 char host_addr[INET_ADDRSTRLEN], guest_addr[INET_ADDRSTRLEN];
188 if (inet_ntop(AF_INET, &fwd->host_addr, host_addr, sizeof(host_addr)) ==
189 NULL) {
190 perror("fatal: inet_ntop");
191 exit(EXIT_FAILURE);
192 }
193 if (inet_ntop(AF_INET, &fwd->guest_addr, guest_addr, sizeof(guest_addr)) ==
194 NULL) {
195 perror("fatal: inet_ntop");
196 exit(EXIT_FAILURE);
197 }
198 json_object_set_number(entry_object, "id", fwd->id);
199 json_object_set_string(entry_object, "proto", fwd->is_udp ? "udp" : "tcp");
200 json_object_set_string(entry_object, "host_addr", host_addr);
201 json_object_set_number(entry_object, "host_port", fwd->host_port);
202 json_object_set_string(entry_object, "guest_addr", guest_addr);
203 json_object_set_number(entry_object, "guest_port", fwd->guest_port);
204 /* json_array_append_value does not copy passed value */
205 if (json_array_append_value(entries_array, entry_value) != JSONSuccess) {
206 fprintf(stderr, "fatal: json_array_append_value\n");
207 exit(EXIT_FAILURE);
208 }
188209 }
189210
190211 /*
191212 Handler for list_hostfwd.
192213 e.g. {"execute": "list_hostfwd"}
193214 */
194 static int api_handle_req_list_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, JSON_Object *jo)
195 {
196 int wrc = 0;
197 struct api_hostfwd *fwd = NULL;
198 JSON_Value *root_value = json_value_init_object(), *entries_value = json_value_init_array();
199 JSON_Object *root_object = json_value_get_object(root_value);
200 JSON_Array *entries_array = json_array(entries_value);
201 char *serialized_string = NULL;
202 g_list_foreach(ctx->hostfwds, api_handle_req_list_hostfwd_foreach, entries_array);
203 json_object_set_value(root_object, "entries", entries_value);
204 serialized_string = json_serialize_to_string(root_value);
205 wrc = write(fd, serialized_string, strlen(serialized_string));
206 finish:
207 json_free_serialized_string(serialized_string);
208 json_value_free(root_value);
209 return wrc;
210 }
211
212 static int api_handle_remove_list_hostfwd_find(gconstpointer gcp_fwd, gconstpointer gcp_id)
213 {
214 struct api_hostfwd *fwd = (struct api_hostfwd *)gcp_fwd;
215 int id = *(int *)gcp_id;
216 return id == fwd->id ? 0 : 1;
215 static int api_handle_req_list_hostfwd(Slirp *slirp, int fd,
216 struct api_ctx *ctx, JSON_Object *jo)
217 {
218 int wrc = 0;
219 JSON_Value *root_value = json_value_init_object(),
220 *entries_value = json_value_init_array();
221 JSON_Object *root_object = json_value_get_object(root_value);
222 JSON_Array *entries_array = json_array(entries_value);
223 char *serialized_string = NULL;
224 g_list_foreach(ctx->hostfwds, api_handle_req_list_hostfwd_foreach,
225 entries_array);
226 json_object_set_value(root_object, "entries", entries_value);
227 serialized_string = json_serialize_to_string(root_value);
228 wrc = write(fd, serialized_string, strlen(serialized_string));
229 json_free_serialized_string(serialized_string);
230 json_value_free(root_value);
231 return wrc;
232 }
233
234 static int api_handle_remove_list_hostfwd_find(gconstpointer gcp_fwd,
235 gconstpointer gcp_id)
236 {
237 struct api_hostfwd *fwd = (struct api_hostfwd *)gcp_fwd;
238 int id = *(int *)gcp_id;
239 return id == fwd->id ? 0 : 1;
217240 }
218241
219242 /*
220243 Handler for remove_hostfwd.
221244 e.g. {"execute": "remove_hostfwd", "arguments": {"id": 42}}
222245 */
223 static int api_handle_req_remove_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, JSON_Object *jo)
224 {
225 int wrc = 0;
226 int id = (int)json_object_dotget_number(jo, "arguments.id");
227 GList *found = g_list_find_custom(ctx->hostfwds, &id, api_handle_remove_list_hostfwd_find);
228 if (found == NULL) {
229 const char *err = "{\"error\":{\"desc\":\"bad request: remove_hostfwd: bad arguments.id\"}}";
230 wrc = write(fd, err, strlen(err));
231 } else {
232 struct api_hostfwd *fwd = found->data;
233 const char *api_ok = "{\"return\":{}}";
234 if (slirp_remove_hostfwd(slirp, fwd->is_udp, fwd->host_addr, fwd->host_port) < 0) {
235 const char *err =
236 "{\"error\":{\"desc\":\"bad request: remove_hostfwd: slirp_remove_hostfwd failed\"}}";
237 wrc = write(fd, err, strlen(err));
238 } else {
239 ctx->hostfwds = g_list_remove(ctx->hostfwds, fwd);
240 g_free(fwd);
241 wrc = write(fd, api_ok, strlen(api_ok));
242 }
243 }
244 return wrc;
246 static int api_handle_req_remove_hostfwd(Slirp *slirp, int fd,
247 struct api_ctx *ctx, JSON_Object *jo)
248 {
249 int wrc = 0;
250 int id = (int)json_object_dotget_number(jo, "arguments.id");
251 GList *found = g_list_find_custom(ctx->hostfwds, &id,
252 api_handle_remove_list_hostfwd_find);
253 if (found == NULL) {
254 const char *err = "{\"error\":{\"desc\":\"bad request: remove_hostfwd: "
255 "bad arguments.id\"}}";
256 wrc = write(fd, err, strlen(err));
257 } else {
258 struct api_hostfwd *fwd = found->data;
259 const char *api_ok = "{\"return\":{}}";
260 if (slirp_remove_hostfwd(slirp, fwd->is_udp, fwd->host_addr,
261 fwd->host_port) < 0) {
262 const char *err = "{\"error\":{\"desc\":\"bad request: "
263 "remove_hostfwd: slirp_remove_hostfwd failed\"}}";
264 wrc = write(fd, err, strlen(err));
265 } else {
266 ctx->hostfwds = g_list_remove(ctx->hostfwds, fwd);
267 g_free(fwd);
268 wrc = write(fd, api_ok, strlen(api_ok));
269 }
270 }
271 return wrc;
245272 }
246273
247274 static int api_handle_req(Slirp *slirp, int fd, struct api_ctx *ctx)
248275 {
249 JSON_Value *jv = NULL;
250 JSON_Object *jo = NULL;
251 const char *execute = NULL;
252 int wrc = 0;
253 if ((jv = json_parse_string((const char *)ctx->buf)) == NULL) {
254 const char *err = "{\"error\":{\"desc\":\"bad request: cannot parse JSON\"}}";
255 wrc = write(fd, err, strlen(err));
256 goto finish;
257 }
258 if ((jo = json_object(jv)) == NULL) {
259 const char *err = "{\"error\":{\"desc\":\"bad request: json_object() failed\"}}";
260 wrc = write(fd, err, strlen(err));
261 goto finish;
262 }
263 /* TODO: json_validate */
264 if ((execute = json_object_get_string(jo, "execute")) == NULL) {
265 const char *err = "{\"error\":{\"desc\":\"bad request: no execute found\"}}";
266 wrc = write(fd, err, strlen(err));
267 goto finish;
268 }
269 if ((strcmp(execute, "add_hostfwd")) == 0) {
270 wrc = api_handle_req_add_hostfwd(slirp, fd, ctx, jo);
271 } else if ((strcmp(execute, "list_hostfwd")) == 0) {
272 wrc = api_handle_req_list_hostfwd(slirp, fd, ctx, jo);
273 } else if ((strcmp(execute, "remove_hostfwd")) == 0) {
274 wrc = api_handle_req_remove_hostfwd(slirp, fd, ctx, jo);
275 } else {
276 const char *err = "{\"error\":{\"desc\":\"bad request: unknown execute\"}}";
277 wrc = write(fd, err, strlen(err));
278 goto finish;
279 }
280 finish:
281 if (jv != NULL) {
282 json_value_free(jv);
283 }
284 return wrc;
276 JSON_Value *jv = NULL;
277 JSON_Object *jo = NULL;
278 const char *execute = NULL;
279 int wrc = 0;
280 if ((jv = json_parse_string((const char *)ctx->buf)) == NULL) {
281 const char *err =
282 "{\"error\":{\"desc\":\"bad request: cannot parse JSON\"}}";
283 wrc = write(fd, err, strlen(err));
284 goto finish;
285 }
286 if ((jo = json_object(jv)) == NULL) {
287 const char *err =
288 "{\"error\":{\"desc\":\"bad request: json_object() failed\"}}";
289 wrc = write(fd, err, strlen(err));
290 goto finish;
291 }
292 /* TODO: json_validate */
293 if ((execute = json_object_get_string(jo, "execute")) == NULL) {
294 const char *err =
295 "{\"error\":{\"desc\":\"bad request: no execute found\"}}";
296 wrc = write(fd, err, strlen(err));
297 goto finish;
298 }
299 if ((strcmp(execute, "add_hostfwd")) == 0) {
300 wrc = api_handle_req_add_hostfwd(slirp, fd, ctx, jo);
301 } else if ((strcmp(execute, "list_hostfwd")) == 0) {
302 wrc = api_handle_req_list_hostfwd(slirp, fd, ctx, jo);
303 } else if ((strcmp(execute, "remove_hostfwd")) == 0) {
304 wrc = api_handle_req_remove_hostfwd(slirp, fd, ctx, jo);
305 } else {
306 const char *err =
307 "{\"error\":{\"desc\":\"bad request: unknown execute\"}}";
308 wrc = write(fd, err, strlen(err));
309 goto finish;
310 }
311 finish:
312 if (jv != NULL) {
313 json_value_free(jv);
314 }
315 return wrc;
285316 }
286317
287318 /*
290321 */
291322 int api_handler(Slirp *slirp, int listenfd, struct api_ctx *ctx)
292323 {
293 struct sockaddr_un addr;
294 socklen_t addrlen = sizeof(struct sockaddr_un);
295 int fd;
296 int rc = 0, wrc = 0;
297 ssize_t len;
298 memset(&addr, 0, sizeof(addr));
299 if ((fd = accept(listenfd, (struct sockaddr *)&addr, &addrlen)) < 0) {
300 perror("api_handler: accept");
301 return -1;
302 }
303 if ((len = read(fd, ctx->buf, ctx->buflen)) < 0) {
304 perror("api_handler: read");
305 rc = len;
306 goto finish;
307 }
308 if (len == ctx->buflen) {
309 const char *err = "{\"error\":{\"desc\":\"bad request: too large message\"}}";
310 fprintf(stderr, "api_handler: too large message (>= %ld bytes)\n", len);
311 wrc = write(fd, err, strlen(err));
312 rc = -1;
313 goto finish;
314 }
315 ctx->buf[len] = 0;
316 fprintf(stderr, "api_handler: got request: %s\n", ctx->buf);
317 wrc = api_handle_req(slirp, fd, ctx);
318 finish:
319 shutdown(fd, SHUT_RDWR);
320 if (rc == 0 && wrc != 0) {
321 rc = wrc;
322 }
323 close(fd);
324 return rc;
325 }
324 struct sockaddr_un addr;
325 socklen_t addrlen = sizeof(struct sockaddr_un);
326 int fd;
327 int rc = 0, wrc = 0;
328 ssize_t len;
329 memset(&addr, 0, sizeof(addr));
330 if ((fd = accept(listenfd, (struct sockaddr *)&addr, &addrlen)) < 0) {
331 perror("api_handler: accept");
332 return -1;
333 }
334 if ((len = read(fd, ctx->buf, ctx->buflen)) < 0) {
335 perror("api_handler: read");
336 rc = len;
337 goto finish;
338 }
339 if (len == ctx->buflen) {
340 const char *err =
341 "{\"error\":{\"desc\":\"bad request: too large message\"}}";
342 fprintf(stderr, "api_handler: too large message (>= %ld bytes)\n", len);
343 wrc = write(fd, err, strlen(err));
344 rc = -1;
345 goto finish;
346 }
347 ctx->buf[len] = 0;
348 fprintf(stderr, "api_handler: got request: %s\n", ctx->buf);
349 wrc = api_handle_req(slirp, fd, ctx);
350 finish:
351 shutdown(fd, SHUT_RDWR);
352 if (rc == 0 && wrc != 0) {
353 rc = wrc;
354 }
355 close(fd);
356 return rc;
357 }
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
01 #ifndef SLIRP4NETNS_API_H
12 # define SLIRP4NETNS_API_H
23 int api_bindlisten(const char *api_socket);
00 AC_PREREQ([2.69])
1 AC_INIT([slirp4netns], [0.3.2], [https://github.com/rootless-containers/slirp4netns/issues])
1 AC_INIT([slirp4netns], [1.0.1], [https://github.com/rootless-containers/slirp4netns/issues])
22 AC_CONFIG_SRCDIR([main.c])
33 AC_CONFIG_HEADERS([config.h])
44
77
88 AM_INIT_AUTOMAKE([1.9 foreign subdir-objects])
99
10 AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/timeb.h unistd.h getopt.h])
10 AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h sys/socket.h sys/timeb.h unistd.h getopt.h])
1111
1212 AC_CHECK_HEADER_STDBOOL
1313 AC_C_INLINE
2424 AC_TYPE_UINT8_T
2525
2626 AC_FUNC_ALLOCA
27 AC_FUNC_STRTOD
2728 AC_FUNC_FORK
2829 AC_FUNC_MALLOC
2930 AC_FUNC_REALLOC
30 AC_CHECK_FUNCS([atexit clock_gettime inet_ntoa memmove memset socket strchr strdup strerror strstr strtol getopt_long])
31 AC_CHECK_FUNCS([atexit clock_gettime dup2 getopt_long inet_ntoa memmove memset mkdir regcomp rmdir socket strcasecmp strchr strdup strerror strstr strtol strtoul])
3132
3233 PKG_CHECK_MODULES(GLIB, glib-2.0)
34 PKG_CHECK_MODULES(SLIRP, slirp >= 4.1.0)
35 PKG_CHECK_MODULES(LIBCAP, libcap)
36 PKG_CHECK_MODULES(LIBSECCOMP, libseccomp)
3337
3438 AC_CONFIG_FILES([Makefile])
3539 AC_OUTPUT
0 #!/bin/bash
1 # release.sh: configurable signed-artefact release script
2 # Copyright (C) 2016-2019 SUSE LLC.
3 #
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8 set -Eeuo pipefail
9
10 ## --->
11 # Project-specific options and functions. In *theory* you shouldn't need to
12 # touch anything else in this script in order to use this elsewhere.
13 project="slirp4netns"
14 root="$(readlink -f "$(dirname "${BASH_SOURCE}")/..")"
15
16 # Make pushd and popd silent.
17 function pushd() { command pushd "$@" &>/dev/null ; }
18 function popd() { command popd "$@" &>/dev/null ; }
19
20 # These functions allow you to configure how the defaults are computed.
21 function get_arch() { uname -m ; }
22 function get_version() { echo '@VERSION@' | "$root/config.status" --file - ; }
23
24 # Any pre-configuration steps should be done here -- for instance ./configure.
25 function setup_project() {
26 pushd "$root"
27 [ -x ./configure ] || ./autogen.sh
28 ./configure LDFLAGS="-static" --prefix=/ --bindir=/bin
29 popd
30 }
31
32 # This function takes an output path as an argument, where the built
33 # (preferably static) binary should be placed.
34 function build_project() {
35 tmprootfs="$(mktemp -d --tmpdir "$project-build.XXXXXX")"
36
37 make -C "$root" clean all install DESTDIR="$tmprootfs"
38
39 mv "$tmprootfs/bin/slirp4netns" "$1"
40 rm -rf "$tmprootfs"
41 }
42 # End of the easy-to-configure portion.
43 ## <---
44
45 # Print usage information.
46 function usage() {
47 echo "usage: release.sh [-h] [-v <version>] [-c <commit>] [-o <output-dir>]" >&2
48 echo " [-H <hashcmd>] [-S <gpg-key>]" >&2
49 }
50
51 # Log something to stderr.
52 function log() {
53 echo "[*]" "$@" >&2
54 }
55
56 # Log something to stderr and then exit with 0.
57 function quit() {
58 log "$@"
59 exit 0
60 }
61
62 # Conduct a sanity-check to make sure that GPG provided with the given
63 # arguments can sign something. Inability to sign things is not a fatal error.
64 function gpg_cansign() {
65 gpg "$@" --clear-sign </dev/null >/dev/null
66 }
67
68 # When creating releases we need to build (ideally static) binaries, an archive
69 # of the current commit, and generate detached signatures for both.
70 keyid=""
71 version=""
72 arch=""
73 commit="HEAD"
74 hashcmd="sha256sum"
75 while getopts ":h:v:c:o:S:H:" opt; do
76 case "$opt" in
77 S)
78 keyid="$OPTARG"
79 ;;
80 c)
81 commit="$OPTARG"
82 ;;
83 o)
84 outputdir="$OPTARG"
85 ;;
86 v)
87 version="$OPTARG"
88 ;;
89 H)
90 hashcmd="$OPTARG"
91 ;;
92 h)
93 usage ; exit 0
94 ;;
95 \:)
96 echo "Missing argument: -$OPTARG" >&2
97 usage ; exit 1
98 ;;
99 \?)
100 echo "Invalid option: -$OPTARG" >&2
101 usage ; exit 1
102 ;;
103 esac
104 done
105
106 # Run project setup first...
107 ( set -x ; setup_project )
108
109 # Generate the defaults for version and so on *after* argument parsing and
110 # setup_project, to avoid calling get_version() needlessly.
111 version="${version:-$(get_version)}"
112 arch="${arch:-$(get_arch)}"
113 outputdir="${outputdir:-release/$version}"
114
115 log "[[ $project ]]"
116 log "version: $version"
117 log "commit: $commit"
118 log "output_dir: $outputdir"
119 log "key: ${keyid:-(default)}"
120 log "hash_cmd: $hashcmd"
121
122 # Make explicit what we're doing.
123 set -x
124
125 # Make the release directory.
126 rm -rf "$outputdir" && mkdir -p "$outputdir"
127
128 # Build project.
129 build_project "$outputdir/$project.$arch"
130
131 # Generate new archive.
132 git archive --format=tar --prefix="$project-$version/" "$commit" | xz > "$outputdir/$project.tar.xz"
133
134 # Generate sha256 checksums for both.
135 ( cd "$outputdir" ; "$hashcmd" "$project".{"$arch",tar.xz} > "$project.$hashcmd" ; )
136
137 # Set up the gpgflags.
138 gpgflags=()
139 [[ -z "$keyid" ]] || gpgflags+=("--default-key=$keyid")
140 gpg_cansign "${gpgflags[@]}" || quit "Could not find suitable GPG key, skipping signing step."
141
142 # Sign everything.
143 gpg "${gpgflags[@]}" --detach-sign --armor "$outputdir/$project.$arch"
144 gpg "${gpgflags[@]}" --detach-sign --armor "$outputdir/$project.tar.xz"
145 gpg "${gpgflags[@]}" --clear-sign --armor \
146 --output "$outputdir/$project.$hashcmd"{.tmp,} && \
147 mv "$outputdir/$project.$hashcmd"{.tmp,}
+677
-510
main.c less more
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
01 #define _GNU_SOURCE
12 #include "config.h"
23 #include <stdio.h>
1718 #include <getopt.h>
1819 #include <stdbool.h>
1920 #include <regex.h>
21 #include <libslirp.h>
2022 #include "slirp4netns.h"
2123
2224 #define DEFAULT_MTU (1500)
2325 #define DEFAULT_CIDR ("10.0.2.0/24")
24 #define DEFAULT_VHOST_OFFSET (2) // 10.0.2.2
25 #define DEFAULT_VDHCPSTART_OFFSET (15) // 10.0.2.15
26 #define DEFAULT_VNAMESERVER_OFFSET (3) // 10.0.2.3
27 #define DEFAULT_RECOMMENDED_VGUEST_OFFSET (100) // 10.0.2.100
26 #define DEFAULT_VHOST_OFFSET (2) // 10.0.2.2
27 #define DEFAULT_VDHCPSTART_OFFSET (15) // 10.0.2.15
28 #define DEFAULT_VNAMESERVER_OFFSET (3) // 10.0.2.3
29 #define DEFAULT_RECOMMENDED_VGUEST_OFFSET (100) // 10.0.2.100
30 #define DEFAULT_NETNS_TYPE ("pid")
2831 #define NETWORK_PREFIX_MIN (1)
29 // >=26 is not supported because the recommended guest IP is set to network addr + 100 .
32 // >=26 is not supported because the recommended guest IP is set to network addr
33 // + 100 .
3034 #define NETWORK_PREFIX_MAX (25)
3135
32 static int nsenter(pid_t target_pid)
33 {
34 char userns[32], netns[32];
35 int usernsfd, netnsfd;
36 snprintf(userns, sizeof(userns), "/proc/%d/ns/user", target_pid);
37 snprintf(netns, sizeof(netns), "/proc/%d/ns/net", target_pid);
38 if ((usernsfd = open(userns, O_RDONLY)) < 0) {
39 perror(userns);
40 return usernsfd;
41 }
42 if ((netnsfd = open(netns, O_RDONLY)) < 0) {
43 perror(netns);
44 return netnsfd;
45 }
46 setns(usernsfd, CLONE_NEWUSER);
47 if (setns(netnsfd, CLONE_NEWNET) < 0) {
48 perror("setns(CLONE_NEWNET)");
49 return -1;
50 }
51 close(usernsfd);
52 close(netnsfd);
53 return 0;
36 static int nsenter(pid_t target_pid, char *netns, char *userns,
37 bool only_userns)
38 {
39 int usernsfd = -1, netnsfd = -1;
40 if (!only_userns && !netns) {
41 if (asprintf(&netns, "/proc/%d/ns/net", target_pid) < 0) {
42 perror("cannot get netns path");
43 return -1;
44 }
45 }
46 if (!userns && target_pid) {
47 if (asprintf(&userns, "/proc/%d/ns/user", target_pid) < 0) {
48 perror("cannot get userns path");
49 return -1;
50 }
51 }
52 if (!only_userns && (netnsfd = open(netns, O_RDONLY)) < 0) {
53 perror(netns);
54 return netnsfd;
55 }
56 if (userns && (usernsfd = open(userns, O_RDONLY)) < 0) {
57 perror(userns);
58 return usernsfd;
59 }
60
61 if (usernsfd != -1) {
62 int r = setns(usernsfd, CLONE_NEWUSER);
63 if (only_userns && r < 0) {
64 perror("setns(CLONE_NEWUSER)");
65 return -1;
66 }
67 close(usernsfd);
68 }
69 if (netnsfd != -1 && setns(netnsfd, CLONE_NEWNET) < 0) {
70 perror("setns(CLONE_NEWNET)");
71 return -1;
72 }
73 close(netnsfd);
74 return 0;
5475 }
5576
5677 static int open_tap(const char *tapname)
5778 {
58 int fd;
59 struct ifreq ifr;
60 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
61 perror("open(\"/dev/net/tun\")");
62 return fd;
63 }
64 memset(&ifr, 0, sizeof(ifr));
65 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
66 strncpy(ifr.ifr_name, tapname, sizeof(ifr.ifr_name) - 1);
67 if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
68 perror("ioctl(TUNSETIFF)");
69 close(fd);
70 return -1;
71 }
72 return fd;
79 int fd;
80 struct ifreq ifr;
81 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
82 perror("open(\"/dev/net/tun\")");
83 return fd;
84 }
85 memset(&ifr, 0, sizeof(ifr));
86 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
87 strncpy(ifr.ifr_name, tapname, sizeof(ifr.ifr_name) - 1);
88 if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
89 perror("ioctl(TUNSETIFF)");
90 close(fd);
91 return -1;
92 }
93 return fd;
7394 }
7495
7596 static int sendfd(int sock, int fd)
7697 {
77 ssize_t rc;
78 struct msghdr msg;
79 struct cmsghdr *cmsg;
80 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
81 struct iovec iov;
82 char dummy = '\0';
83 memset(&msg, 0, sizeof(msg));
84 iov.iov_base = &dummy;
85 iov.iov_len = 1;
86 msg.msg_iov = &iov;
87 msg.msg_iovlen = 1;
88 msg.msg_control = cmsgbuf;
89 msg.msg_controllen = sizeof(cmsgbuf);
90 cmsg = CMSG_FIRSTHDR(&msg);
91 cmsg->cmsg_level = SOL_SOCKET;
92 cmsg->cmsg_type = SCM_RIGHTS;
93 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
94 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
95 msg.msg_controllen = cmsg->cmsg_len;
96 if ((rc = sendmsg(sock, &msg, 0)) < 0) {
97 perror("sendmsg");
98 }
99 return rc;
100 }
101
102 static int configure_network(const char *tapname, struct slirp4netns_config *cfg)
103 {
104 struct rtentry route;
105 struct ifreq ifr;
106 struct sockaddr_in *sai = (struct sockaddr_in *)&ifr.ifr_addr;
107 int sockfd;
108
109 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
110 if (sockfd < 0) {
111 perror("cannot create socket");
112 return -1;
113 }
114
115 memset(&ifr, 0, sizeof(ifr));
116 ifr.ifr_flags = IFF_UP | IFF_RUNNING;
117 strncpy(ifr.ifr_name, tapname, sizeof(ifr.ifr_name) - 1);
118
119 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
120 perror("cannot set device up");
121 return -1;
122 }
123
124 ifr.ifr_mtu = (int)cfg->mtu;
125 if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
126 perror("cannot set MTU");
127 return -1;
128 }
129
130 sai->sin_family = AF_INET;
131 sai->sin_port = 0;
132 sai->sin_addr = cfg->recommended_vguest;
133
134 if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
135 perror("cannot set device address");
136 return -1;
137 }
138
139 sai->sin_addr = cfg->vnetmask;
140 if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
141 perror("cannot set device netmask");
142 return -1;
143 }
144
145 memset(&route, 0, sizeof(route));
146 sai = (struct sockaddr_in *)&route.rt_gateway;
147 sai->sin_family = AF_INET;
148 sai->sin_addr = cfg->vhost;
149 sai = (struct sockaddr_in *)&route.rt_dst;
150 sai->sin_family = AF_INET;
151 sai->sin_addr.s_addr = INADDR_ANY;
152 sai = (struct sockaddr_in *)&route.rt_genmask;
153 sai->sin_family = AF_INET;
154 sai->sin_addr.s_addr = INADDR_ANY;
155
156 route.rt_flags = RTF_UP | RTF_GATEWAY;
157 route.rt_metric = 0;
158 route.rt_dev = (char *)tapname;
159
160 if (ioctl(sockfd, SIOCADDRT, &route) < 0) {
161 perror("set route");
162 return -1;
163 }
164 return 0;
165 }
166
167 static int child(int sock, pid_t target_pid, bool do_config_network, const char *tapname, int ready_fd,
168 struct slirp4netns_config *cfg)
169 {
170 int rc, tapfd;
171 if ((rc = nsenter(target_pid)) < 0) {
172 return rc;
173 }
174 if ((tapfd = open_tap(tapname)) < 0) {
175 return tapfd;
176 }
177 if (do_config_network && configure_network(tapname, cfg) < 0) {
178 return -1;
179 }
180 if (ready_fd >= 0) {
181 do
182 rc = write(ready_fd, "1", 1);
183 while (rc < 0 && errno == EINTR);
184 close(ready_fd);
185 }
186 if (sendfd(sock, tapfd) < 0) {
187 close(tapfd);
188 close(sock);
189 return -1;
190 }
191 fprintf(stderr, "sent tapfd=%d for %s\n", tapfd, tapname);
192 close(sock);
193 return 0;
98 ssize_t rc;
99 struct msghdr msg;
100 struct cmsghdr *cmsg;
101 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
102 struct iovec iov;
103 char dummy = '\0';
104 memset(&msg, 0, sizeof(msg));
105 iov.iov_base = &dummy;
106 iov.iov_len = 1;
107 msg.msg_iov = &iov;
108 msg.msg_iovlen = 1;
109 msg.msg_control = cmsgbuf;
110 msg.msg_controllen = sizeof(cmsgbuf);
111 cmsg = CMSG_FIRSTHDR(&msg);
112 cmsg->cmsg_level = SOL_SOCKET;
113 cmsg->cmsg_type = SCM_RIGHTS;
114 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
115 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
116 msg.msg_controllen = cmsg->cmsg_len;
117 if ((rc = sendmsg(sock, &msg, 0)) < 0) {
118 perror("sendmsg");
119 }
120 return rc;
121 }
122
123 static int configure_network(const char *tapname,
124 struct slirp4netns_config *cfg)
125 {
126 struct rtentry route;
127 struct ifreq ifr;
128 struct sockaddr_in *sai = (struct sockaddr_in *)&ifr.ifr_addr;
129 int sockfd;
130
131 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
132 if (sockfd < 0) {
133 perror("cannot create socket");
134 return -1;
135 }
136
137 // set loopback device to UP
138 struct ifreq ifr_lo = { .ifr_name = "lo",
139 .ifr_flags = IFF_UP | IFF_RUNNING };
140 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr_lo) < 0) {
141 perror("cannot set device up");
142 return -1;
143 }
144
145 memset(&ifr, 0, sizeof(ifr));
146 ifr.ifr_flags = IFF_UP | IFF_RUNNING;
147 strncpy(ifr.ifr_name, tapname, sizeof(ifr.ifr_name) - 1);
148
149 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
150 perror("cannot set device up");
151 return -1;
152 }
153
154 ifr.ifr_mtu = (int)cfg->mtu;
155 if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
156 perror("cannot set MTU");
157 return -1;
158 }
159
160 sai->sin_family = AF_INET;
161 sai->sin_port = 0;
162 sai->sin_addr = cfg->recommended_vguest;
163
164 if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
165 perror("cannot set device address");
166 return -1;
167 }
168
169 sai->sin_addr = cfg->vnetmask;
170 if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
171 perror("cannot set device netmask");
172 return -1;
173 }
174
175 memset(&route, 0, sizeof(route));
176 sai = (struct sockaddr_in *)&route.rt_gateway;
177 sai->sin_family = AF_INET;
178 sai->sin_addr = cfg->vhost;
179 sai = (struct sockaddr_in *)&route.rt_dst;
180 sai->sin_family = AF_INET;
181 sai->sin_addr.s_addr = INADDR_ANY;
182 sai = (struct sockaddr_in *)&route.rt_genmask;
183 sai->sin_family = AF_INET;
184 sai->sin_addr.s_addr = INADDR_ANY;
185
186 route.rt_flags = RTF_UP | RTF_GATEWAY;
187 route.rt_metric = 0;
188 route.rt_dev = (char *)tapname;
189
190 if (ioctl(sockfd, SIOCADDRT, &route) < 0) {
191 perror("set route");
192 return -1;
193 }
194 return 0;
195 }
196
197 static int child(int sock, pid_t target_pid, bool do_config_network,
198 const char *tapname, char *netns_path, char *userns_path,
199 struct slirp4netns_config *cfg)
200 {
201 int rc, tapfd;
202 if ((rc = nsenter(target_pid, netns_path, userns_path, false)) < 0) {
203 return rc;
204 }
205 if ((tapfd = open_tap(tapname)) < 0) {
206 return tapfd;
207 }
208 if (do_config_network && configure_network(tapname, cfg) < 0) {
209 return -1;
210 }
211 if (sendfd(sock, tapfd) < 0) {
212 close(tapfd);
213 close(sock);
214 return -1;
215 }
216 fprintf(stderr, "sent tapfd=%d for %s\n", tapfd, tapname);
217 close(sock);
218 return 0;
194219 }
195220
196221 static int recvfd(int sock)
197222 {
198 int fd;
199 ssize_t rc;
200 struct msghdr msg;
201 struct cmsghdr *cmsg;
202 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
203 struct iovec iov;
204 char dummy = '\0';
205 memset(&msg, 0, sizeof(msg));
206 iov.iov_base = &dummy;
207 iov.iov_len = 1;
208 msg.msg_iov = &iov;
209 msg.msg_iovlen = 1;
210 msg.msg_control = cmsgbuf;
211 msg.msg_controllen = sizeof(cmsgbuf);
212 if ((rc = recvmsg(sock, &msg, 0)) < 0) {
213 perror("recvmsg");
214 return (int)rc;
215 }
216 if (rc == 0) {
217 fprintf(stderr, "the message is empty\n");
218 return -1;
219 }
220 cmsg = CMSG_FIRSTHDR(&msg);
221 if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS) {
222 fprintf(stderr, "the message does not contain fd\n");
223 return -1;
224 }
225 memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
226 return fd;
227 }
228
229 static int parent(int sock, int exit_fd, const char *api_socket, struct slirp4netns_config *cfg)
230 {
231 int rc, tapfd;
232 if ((tapfd = recvfd(sock)) < 0) {
233 return tapfd;
234 }
235 fprintf(stderr, "received tapfd=%d\n", tapfd);
236 close(sock);
237 printf("Starting slirp\n");
238 printf("* MTU: %d\n", cfg->mtu);
239 printf("* Network: %s\n", inet_ntoa(cfg->vnetwork));
240 printf("* Netmask: %s\n", inet_ntoa(cfg->vnetmask));
241 printf("* Gateway: %s\n", inet_ntoa(cfg->vhost));
242 printf("* DNS: %s\n", inet_ntoa(cfg->vnameserver));
243 printf("* Recommended IP: %s\n", inet_ntoa(cfg->recommended_vguest));
244 if (api_socket != NULL) {
245 printf("* API Socket: %s\n", api_socket);
246 }
247 if (!cfg->disable_host_loopback) {
248 printf
249 ("WARNING: 127.0.0.1:* on the host is accessible as %s (set --disable-host-loopback to prohibit connecting to 127.0.0.1:*)\n",
250 inet_ntoa(cfg->vhost));
251 }
252 if ((rc = do_slirp(tapfd, exit_fd, api_socket, cfg)) < 0) {
253 fprintf(stderr, "do_slirp failed\n");
254 close(tapfd);
255 return rc;
256 }
257 /* NOT REACHED */
258 return 0;
223 int fd;
224 ssize_t rc;
225 struct msghdr msg;
226 struct cmsghdr *cmsg;
227 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
228 struct iovec iov;
229 char dummy = '\0';
230 memset(&msg, 0, sizeof(msg));
231 iov.iov_base = &dummy;
232 iov.iov_len = 1;
233 msg.msg_iov = &iov;
234 msg.msg_iovlen = 1;
235 msg.msg_control = cmsgbuf;
236 msg.msg_controllen = sizeof(cmsgbuf);
237 if ((rc = recvmsg(sock, &msg, 0)) < 0) {
238 perror("recvmsg");
239 return (int)rc;
240 }
241 if (rc == 0) {
242 fprintf(stderr, "the message is empty\n");
243 return -1;
244 }
245 cmsg = CMSG_FIRSTHDR(&msg);
246 if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS) {
247 fprintf(stderr, "the message does not contain fd\n");
248 return -1;
249 }
250 memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
251 return fd;
252 }
253
254 static int parent(int sock, int ready_fd, int exit_fd, const char *api_socket,
255 struct slirp4netns_config *cfg, pid_t target_pid)
256 {
257 int rc, tapfd;
258 if ((tapfd = recvfd(sock)) < 0) {
259 return tapfd;
260 }
261 fprintf(stderr, "received tapfd=%d\n", tapfd);
262 close(sock);
263 printf("Starting slirp\n");
264 printf("* MTU: %d\n", cfg->mtu);
265 printf("* Network: %s\n", inet_ntoa(cfg->vnetwork));
266 printf("* Netmask: %s\n", inet_ntoa(cfg->vnetmask));
267 printf("* Gateway: %s\n", inet_ntoa(cfg->vhost));
268 printf("* DNS: %s\n", inet_ntoa(cfg->vnameserver));
269 printf("* Recommended IP: %s\n", inet_ntoa(cfg->recommended_vguest));
270 if (api_socket != NULL) {
271 printf("* API Socket: %s\n", api_socket);
272 }
273 if (!cfg->disable_host_loopback) {
274 printf(
275 "WARNING: 127.0.0.1:* on the host is accessible as %s (set "
276 "--disable-host-loopback to prohibit connecting to 127.0.0.1:*)\n",
277 inet_ntoa(cfg->vhost));
278 }
279 if (cfg->enable_sandbox && geteuid() != 0) {
280 if ((rc = nsenter(target_pid, NULL, NULL, true)) < 0) {
281 close(tapfd);
282 return rc;
283 }
284 if ((rc = setegid(0)) < 0) {
285 fprintf(stderr, "setegid(0)\n");
286 close(tapfd);
287 return rc;
288 }
289 if ((rc = seteuid(0)) < 0) {
290 fprintf(stderr, "seteuid(0)\n");
291 close(tapfd);
292 return rc;
293 }
294 }
295 if ((rc = do_slirp(tapfd, ready_fd, exit_fd, api_socket, cfg)) < 0) {
296 fprintf(stderr, "do_slirp failed\n");
297 close(tapfd);
298 return rc;
299 }
300 /* NOT REACHED */
301 return 0;
259302 }
260303
261304 static void usage(const char *argv0)
262305 {
263 printf("Usage: %s [OPTION]... PID TAPNAME\n", argv0);
264 printf("User-mode networking for unprivileged network namespaces.\n\n");
265 printf("-c, --configure bring up the interface\n");
266 printf("-e, --exit-fd=FD specify the FD for terminating slirp4netns\n");
267 printf("-r, --ready-fd=FD specify the FD to write to when the network is configured\n");
268 printf("-m, --mtu=MTU specify MTU (default=%d, max=65521)\n", DEFAULT_MTU);
269 printf("--cidr=CIDR specify network address CIDR (default=%s)\n", DEFAULT_CIDR);
270 printf("--disable-host-loopback prohibit connecting to 127.0.0.1:* on the host namespace\n");
271 printf("-a, --api-socket=PATH specify API socket path\n");
272 printf("-6, --enable-ipv6 enable IPv6 (experimental)\n");
273 printf("-h, --help show this help and exit\n");
274 printf("-v, --version show version and exit\n");
306 printf("Usage: %s [OPTION]... PID|PATH TAPNAME\n", argv0);
307 printf("User-mode networking for unprivileged network namespaces.\n\n");
308 printf("-c, --configure bring up the interface\n");
309 printf("-e, --exit-fd=FD specify the FD for terminating "
310 "slirp4netns\n");
311 printf("-r, --ready-fd=FD specify the FD to write to when the "
312 "network is configured\n");
313 /* v0.2.0 */
314 printf("-m, --mtu=MTU specify MTU (default=%d, max=65521)\n",
315 DEFAULT_MTU);
316 printf("-6, --enable-ipv6 enable IPv6 (experimental)\n");
317 /* v0.3.0 */
318 printf("-a, --api-socket=PATH specify API socket path\n");
319 printf(
320 "--cidr=CIDR specify network address CIDR (default=%s)\n",
321 DEFAULT_CIDR);
322 printf("--disable-host-loopback prohibit connecting to 127.0.0.1:* on the "
323 "host namespace\n");
324 /* v0.4.0 */
325 printf("--netns-type=TYPE specify network namespace type ([path|pid], "
326 "default=%s)\n",
327 DEFAULT_NETNS_TYPE);
328 printf("--userns-path=PATH specify user namespace path\n");
329 printf(
330 "--enable-sandbox create a new mount namespace (and drop all "
331 "caps except CAP_NET_BIND_SERVICE if running as the root)\n");
332 printf("--enable-seccomp enable seccomp to limit syscalls "
333 "(experimental)\n");
334 /* others */
335 printf("-h, --help show this help and exit\n");
336 printf("-v, --version show version and exit\n");
275337 }
276338
277339 // version output is runc-compatible and machine-parsable
278340 static void version()
279341 {
280 printf("slirp4netns version %s\n", VERSION ? VERSION : PACKAGE_VERSION);
342 printf("slirp4netns version %s\n", VERSION ? VERSION : PACKAGE_VERSION);
281343 #ifdef COMMIT
282 printf("commit: %s\n", COMMIT);
344 printf("commit: %s\n", COMMIT);
283345 #endif
346 printf("libslirp: %s\n", slirp_version_string());
284347 }
285348
286349 struct options {
287 pid_t target_pid; // argv[1]
288 char *tapname; // argv[2]
289 bool do_config_network; // -c
290 int exit_fd; // -e
291 int ready_fd; // -r
292 unsigned int mtu; // -m
293 bool disable_host_loopback; // --disable-host-loopback
294 char *cidr; // --cidr
295 bool enable_ipv6; // -6
296 char *api_socket; // -a
350 pid_t target_pid; // argv[1]
351 char *tapname; // argv[2]
352 bool do_config_network; // -c
353 int exit_fd; // -e
354 int ready_fd; // -r
355 unsigned int mtu; // -m
356 bool disable_host_loopback; // --disable-host-loopback
357 char *cidr; // --cidr
358 bool enable_ipv6; // -6
359 char *api_socket; // -a
360 char *netns_type; // argv[1]
361 char *netns_path; // --netns-path
362 char *userns_path; // --userns-path
363 bool enable_sandbox; // --enable-sandbox
364 bool enable_seccomp; // --enable-seccomp
297365 };
298366
299367 static void options_init(struct options *options)
300368 {
301 memset(options, 0, sizeof(*options));
302 options->exit_fd = options->ready_fd = -1;
303 options->mtu = DEFAULT_MTU;
369 memset(options, 0, sizeof(*options));
370 options->exit_fd = options->ready_fd = -1;
371 options->mtu = DEFAULT_MTU;
304372 }
305373
306374 static void options_destroy(struct options *options)
307375 {
308 if (options->tapname != NULL) {
309 free(options->tapname);
310 options->tapname = NULL;
311 }
312 if (options->cidr != NULL) {
313 free(options->cidr);
314 options->cidr = NULL;
315 }
316 if (options->api_socket != NULL) {
317 free(options->api_socket);
318 options->api_socket = NULL;
319 }
320 // options itself is not freed, because it can be on the stack.
376 if (options->tapname != NULL) {
377 free(options->tapname);
378 options->tapname = NULL;
379 }
380 if (options->cidr != NULL) {
381 free(options->cidr);
382 options->cidr = NULL;
383 }
384 if (options->api_socket != NULL) {
385 free(options->api_socket);
386 options->api_socket = NULL;
387 }
388 if (options->netns_type != NULL) {
389 free(options->netns_type);
390 options->netns_type = NULL;
391 }
392 if (options->netns_path != NULL) {
393 free(options->netns_path);
394 options->netns_path = NULL;
395 }
396 if (options->userns_path != NULL) {
397 free(options->userns_path);
398 options->userns_path = NULL;
399 }
321400 }
322401
323402 // * caller does not need to call options_init()
325404 // * this function calls exit() on an error.
326405 static void parse_args(int argc, char *const argv[], struct options *options)
327406 {
328 int opt;
407 int opt;
408 char *strtol_e = NULL;
409 char *optarg_cidr = NULL;
410 char *optarg_netns_type = NULL;
411 char *optarg_userns_path = NULL;
412 char *optarg_api_socket = NULL;
329413 #define CIDR -42
330414 #define DISABLE_HOST_LOOPBACK -43
331 #define _DEPRECATED_NO_HOST_LOOPBACK -10043 // deprecated in favor of disable-host-loopback
332 const struct option longopts[] = {
333 {"configure", no_argument, NULL, 'c'},
334 {"exit-fd", required_argument, NULL, 'e'},
335 {"ready-fd", required_argument, NULL, 'r'},
336 {"mtu", required_argument, NULL, 'm'},
337 {"cidr", required_argument, NULL, CIDR},
338 {"disable-host-loopback", no_argument, NULL, DISABLE_HOST_LOOPBACK},
339 {"no-host-loopback", no_argument, NULL, _DEPRECATED_NO_HOST_LOOPBACK},
340 {"api-socket", required_argument, NULL, 'a'},
341 {"enable-ipv6", no_argument, NULL, '6'},
342 {"help", no_argument, NULL, 'h'},
343 {"version", no_argument, NULL, 'v'},
344 {0, 0, 0, 0},
345 };
346 options_init(options);
347 while ((opt = getopt_long(argc, argv, "ce:r:m:a:6hv", longopts, NULL)) != -1) {
348 switch (opt) {
349 case 'c':
350 options->do_config_network = true;
351 break;
352 case 'e':
353 errno = 0;
354 options->exit_fd = strtol(optarg, NULL, 10);
355 if (errno) {
356 perror("strtol");
357 usage(argv[0]);
358 exit(EXIT_FAILURE);
359 }
360 break;
361 case 'r':
362 errno = 0;
363 options->ready_fd = strtol(optarg, NULL, 10);
364 if (errno) {
365 perror("strtol");
366 usage(argv[0]);
367 exit(EXIT_FAILURE);
368 }
369 break;
370 case 'm':
371 errno = 0;
372 options->mtu = strtol(optarg, NULL, 10);
373 if (errno) {
374 perror("strtol");
375 usage(argv[0]);
376 exit(EXIT_FAILURE);
377 }
378 break;
379 case CIDR:
380 options->cidr = strdup(optarg);
381 break;
382 case _DEPRECATED_NO_HOST_LOOPBACK:
383 // There was no tagged release with support for --no-host-loopback.
384 // So no one will be affected by removal of --no-host-loopback.
385 printf
386 ("WARNING: --no-host-loopback is deprecated and will be removed in future releases, please use --disable-host-loopback instead.\n");
387 /* FALLTHROUGH */
388 case DISABLE_HOST_LOOPBACK:
389 options->disable_host_loopback = true;
390 break;
391 case 'a':
392 options->api_socket = strdup(optarg);
393 break;
394 case '6':
395 options->enable_ipv6 = true;
396 printf("WARNING: Support for IPv6 is experimental\n");
397 break;
398 case 'h':
399 usage(argv[0]);
400 exit(EXIT_SUCCESS);
401 case 'v':
402 version();
403 exit(EXIT_SUCCESS);
404 default:
405 usage(argv[0]);
406 exit(EXIT_FAILURE);
407 }
408 }
415 #define NETNS_TYPE -44
416 #define USERNS_PATH -45
417 #define ENABLE_SANDBOX -46
418 #define ENABLE_SECCOMP -47
419 #define _DEPRECATED_NO_HOST_LOOPBACK \
420 -10043 // deprecated in favor of disable-host-loopback
421 #define _DEPRECATED_CREATE_SANDBOX \
422 -10044 // deprecated in favor of enable-sandbox
423 const struct option longopts[] = {
424 { "configure", no_argument, NULL, 'c' },
425 { "exit-fd", required_argument, NULL, 'e' },
426 { "ready-fd", required_argument, NULL, 'r' },
427 { "mtu", required_argument, NULL, 'm' },
428 { "cidr", required_argument, NULL, CIDR },
429 { "disable-host-loopback", no_argument, NULL, DISABLE_HOST_LOOPBACK },
430 { "no-host-loopback", no_argument, NULL, _DEPRECATED_NO_HOST_LOOPBACK },
431 { "netns-type", required_argument, NULL, NETNS_TYPE },
432 { "userns-path", required_argument, NULL, USERNS_PATH },
433 { "api-socket", required_argument, NULL, 'a' },
434 { "enable-ipv6", no_argument, NULL, '6' },
435 { "enable-sandbox", no_argument, NULL, ENABLE_SANDBOX },
436 { "create-sandbox", no_argument, NULL, _DEPRECATED_CREATE_SANDBOX },
437 { "enable-seccomp", no_argument, NULL, ENABLE_SECCOMP },
438 { "help", no_argument, NULL, 'h' },
439 { "version", no_argument, NULL, 'v' },
440 { 0, 0, 0, 0 },
441 };
442 options_init(options);
443 /* NOTE: clang-tidy hates strdup(optarg) in the while loop (#112) */
444 while ((opt = getopt_long(argc, argv, "ce:r:m:a:6hv", longopts, NULL)) !=
445 -1) {
446 switch (opt) {
447 case 'c':
448 options->do_config_network = true;
449 break;
450 case 'e':
451 errno = 0;
452 options->exit_fd = strtol(optarg, &strtol_e, 10);
453 if (errno || *strtol_e != '\0' || options->exit_fd < 0) {
454 fprintf(stderr, "exit-fd must be a non-negative integer\n");
455 goto error;
456 }
457 break;
458 case 'r':
459 errno = 0;
460 options->ready_fd = strtol(optarg, &strtol_e, 10);
461 if (errno || *strtol_e != '\0' || options->ready_fd < 0) {
462 fprintf(stderr, "ready-fd must be a non-negative integer\n");
463 goto error;
464 }
465 break;
466 case 'm':
467 errno = 0;
468 options->mtu = strtol(optarg, &strtol_e, 10);
469 if (errno || *strtol_e != '\0' || options->mtu <= 0 ||
470 options->mtu > 65521) {
471 fprintf(stderr, "MTU must be a positive integer (< 65522)\n");
472 goto error;
473 }
474 break;
475 case CIDR:
476 optarg_cidr = optarg;
477 break;
478 case _DEPRECATED_NO_HOST_LOOPBACK:
479 // There was no tagged release with support for --no-host-loopback.
480 // So no one will be affected by removal of --no-host-loopback.
481 printf("WARNING: --no-host-loopback is deprecated and will be "
482 "removed in future releases, please use "
483 "--disable-host-loopback instead.\n");
484 /* FALLTHROUGH */
485 case DISABLE_HOST_LOOPBACK:
486 options->disable_host_loopback = true;
487 break;
488 case _DEPRECATED_CREATE_SANDBOX:
489 // There was no tagged release with support for --create-sandbox.
490 // So no one will be affected by removal of --create-sandbox.
491 printf("WARNING: --create-sandbox is deprecated and will be "
492 "removed in future releases, please use "
493 "--enable-sandbox instead.\n");
494 /* FALLTHROUGH */
495 case ENABLE_SANDBOX:
496 options->enable_sandbox = true;
497 break;
498 case ENABLE_SECCOMP:
499 printf("WARNING: Support for seccomp is experimental\n");
500 options->enable_seccomp = true;
501 break;
502 case NETNS_TYPE:
503 optarg_netns_type = optarg;
504 break;
505 case USERNS_PATH:
506 optarg_userns_path = optarg;
507 if (access(optarg_userns_path, F_OK) == -1) {
508 fprintf(stderr, "userns path doesn't exist: %s\n",
509 optarg_userns_path);
510 goto error;
511 }
512 break;
513 case 'a':
514 optarg_api_socket = optarg;
515 break;
516 case '6':
517 options->enable_ipv6 = true;
518 printf("WARNING: Support for IPv6 is experimental\n");
519 break;
520 case 'h':
521 usage(argv[0]);
522 exit(EXIT_SUCCESS);
523 break;
524 case 'v':
525 version();
526 exit(EXIT_SUCCESS);
527 break;
528 default:
529 goto error;
530 break;
531 }
532 }
533 if (optarg_cidr != NULL) {
534 options->cidr = strdup(optarg_cidr);
535 }
536 if (optarg_netns_type != NULL) {
537 options->netns_type = strdup(optarg_netns_type);
538 }
539 if (optarg_userns_path != NULL) {
540 options->userns_path = strdup(optarg_userns_path);
541 }
542 if (optarg_api_socket != NULL) {
543 options->api_socket = strdup(optarg_api_socket);
544 }
409545 #undef CIDR
410546 #undef DISABLE_HOST_LOOPBACK
547 #undef NETNS_TYPE
548 #undef USERNS_PATH
411549 #undef _DEPRECATED_NO_HOST_LOOPBACK
412 if (options->ready_fd >= 0 && !options->do_config_network) {
413 fprintf(stderr, "the option -r FD requires -c\n");
414 exit(EXIT_FAILURE);
415 }
416 if (options->mtu == 0 || options->mtu > 65521) {
417 fprintf(stderr, "MTU must be a positive integer (< 65522)\n");
418 exit(EXIT_FAILURE);
419 }
420 if (argc - optind < 2) {
421 usage(argv[0]);
422 exit(EXIT_FAILURE);
423 }
424 errno = 0;
425 options->target_pid = strtol(argv[optind], NULL, 10);
426 if (errno != 0) {
427 perror("strtol");
428 usage(argv[0]);
429 exit(EXIT_FAILURE);
430 }
431 options->tapname = strdup(argv[optind + 1]);
432 }
433
434 static int from_regmatch(char *buf, size_t buf_len, regmatch_t match, const char *orig)
435 {
436 size_t len = match.rm_eo - match.rm_so;
437 if (len > buf_len - 1) {
438 return -1;
439 }
440 memset(buf, 0, buf_len);
441 strncpy(buf, &orig[match.rm_so], len);
442 return 0;
443 }
444
445 static int parse_cidr(struct in_addr *network, struct in_addr *netmask, const char *cidr)
446 {
447 int rc = 0;
448 regex_t r;
449 regmatch_t matches[4];
450 size_t nmatch = sizeof(matches) / sizeof(matches[0]);
451 const char *cidr_regex = "^(([0-9]{1,3}\\.){3}[0-9]{1,3})/([0-9]{1,2})$";
452 char snetwork[16], sprefix[16];
453 int prefix;
454 rc = regcomp(&r, cidr_regex, REG_EXTENDED);
455 if (rc != 0) {
456 fprintf(stderr, "internal regex error\n");
457 rc = -1;
458 goto finish;
459 }
460 rc = regexec(&r, cidr, nmatch, matches, 0);
461 if (rc != 0) {
462 fprintf(stderr, "invalid CIDR: %s\n", cidr);
463 rc = -1;
464 goto finish;
465 }
466 rc = from_regmatch(snetwork, sizeof(snetwork), matches[1], cidr);
467 if (rc < 0) {
468 fprintf(stderr, "invalid CIDR: %s\n", cidr);
469 goto finish;
470 }
471 rc = from_regmatch(sprefix, sizeof(sprefix), matches[3], cidr);
472 if (rc < 0) {
473 fprintf(stderr, "invalid CIDR: %s\n", cidr);
474 goto finish;
475 }
476 if (inet_pton(AF_INET, snetwork, network) != 1) {
477 fprintf(stderr, "invalid network address: %s\n", snetwork);
478 rc = -1;
479 goto finish;
480 }
481 errno = 0;
482 prefix = strtoul(sprefix, NULL, 10);
483 if (errno) {
484 fprintf(stderr, "invalid prefix length: %s\n", sprefix);
485 rc = -1;
486 goto finish;
487 }
488 if (prefix < NETWORK_PREFIX_MIN || prefix > NETWORK_PREFIX_MAX) {
489 fprintf(stderr, "prefix length needs to be %d-%d\n", NETWORK_PREFIX_MIN, NETWORK_PREFIX_MAX);
490 rc = -1;
491 goto finish;
492 }
493 netmask->s_addr = htonl(~((1 << (32 - prefix)) - 1));
494 if ((network->s_addr & netmask->s_addr) != network->s_addr) {
495 fprintf(stderr, "CIDR needs to be a network address like 10.0.2.0/24, not like 10.0.2.100/24\n");
496 rc = -1;
497 goto finish;
498 }
499 finish:
500 regfree(&r);
501 return rc;
502 }
503
504 static int slirp4netns_config_from_cidr(struct slirp4netns_config *cfg, const char *cidr)
505 {
506 int rc;
507 rc = parse_cidr(&cfg->vnetwork, &cfg->vnetmask, cidr);
508 if (rc < 0) {
509 goto finish;
510 }
511 cfg->vhost.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_VHOST_OFFSET);
512 cfg->vdhcp_start.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_VDHCPSTART_OFFSET);
513 cfg->vnameserver.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_VNAMESERVER_OFFSET);
514 cfg->recommended_vguest.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_RECOMMENDED_VGUEST_OFFSET);
515 finish:
516 return rc;
517 }
518
519 static int slirp4netns_config_from_options(struct slirp4netns_config *cfg, struct options *opt)
520 {
521 int rc = 0;
522 cfg->mtu = opt->mtu;
523 rc = slirp4netns_config_from_cidr(cfg, opt->cidr == NULL ? DEFAULT_CIDR : opt->cidr);
524 if (rc < 0) {
525 goto finish;
526 }
527 cfg->enable_ipv6 = cfg->enable_ipv6;
528 cfg->disable_host_loopback = opt->disable_host_loopback;
529 finish:
530 return rc;
550 #undef ENABLE_SANDBOX
551 #undef ENABLE_SECCOMP
552 if (argc - optind < 2) {
553 goto error;
554 }
555 if (!options->netns_type ||
556 strcmp(options->netns_type, DEFAULT_NETNS_TYPE) == 0) {
557 errno = 0;
558 options->target_pid = strtol(argv[optind], &strtol_e, 10);
559 if (errno || *strtol_e != '\0' || options->target_pid <= 0) {
560 fprintf(stderr, "PID must be a positive integer\n");
561 goto error;
562 }
563 } else {
564 options->netns_path = strdup(argv[optind]);
565 if (access(options->netns_path, F_OK) == -1) {
566 perror("existing path expected when --netns-type=path");
567 goto error;
568 }
569 }
570 options->tapname = strdup(argv[optind + 1]);
571 return;
572 error:
573 usage(argv[0]);
574 options_destroy(options);
575 exit(EXIT_FAILURE);
576 }
577
578 static int from_regmatch(char *buf, size_t buf_len, regmatch_t match,
579 const char *orig)
580 {
581 size_t len = match.rm_eo - match.rm_so;
582 if (len > buf_len - 1) {
583 return -1;
584 }
585 memset(buf, 0, buf_len);
586 strncpy(buf, &orig[match.rm_so], len);
587 return 0;
588 }
589
590 static int parse_cidr(struct in_addr *network, struct in_addr *netmask,
591 const char *cidr)
592 {
593 int rc = 0;
594 regex_t r;
595 regmatch_t matches[4];
596 size_t nmatch = sizeof(matches) / sizeof(matches[0]);
597 const char *cidr_regex = "^(([0-9]{1,3}\\.){3}[0-9]{1,3})/([0-9]{1,2})$";
598 char snetwork[16], sprefix[16];
599 int prefix;
600 rc = regcomp(&r, cidr_regex, REG_EXTENDED);
601 if (rc != 0) {
602 fprintf(stderr, "internal regex error\n");
603 rc = -1;
604 goto finish;
605 }
606 rc = regexec(&r, cidr, nmatch, matches, 0);
607 if (rc != 0) {
608 fprintf(stderr, "invalid CIDR: %s\n", cidr);
609 rc = -1;
610 goto finish;
611 }
612 rc = from_regmatch(snetwork, sizeof(snetwork), matches[1], cidr);
613 if (rc < 0) {
614 fprintf(stderr, "invalid CIDR: %s\n", cidr);
615 goto finish;
616 }
617 rc = from_regmatch(sprefix, sizeof(sprefix), matches[3], cidr);
618 if (rc < 0) {
619 fprintf(stderr, "invalid CIDR: %s\n", cidr);
620 goto finish;
621 }
622 if (inet_pton(AF_INET, snetwork, network) != 1) {
623 fprintf(stderr, "invalid network address: %s\n", snetwork);
624 rc = -1;
625 goto finish;
626 }
627 errno = 0;
628 prefix = strtoul(sprefix, NULL, 10);
629 if (errno) {
630 fprintf(stderr, "invalid prefix length: %s\n", sprefix);
631 rc = -1;
632 goto finish;
633 }
634 if (prefix < NETWORK_PREFIX_MIN || prefix > NETWORK_PREFIX_MAX) {
635 fprintf(stderr, "prefix length needs to be %d-%d\n", NETWORK_PREFIX_MIN,
636 NETWORK_PREFIX_MAX);
637 rc = -1;
638 goto finish;
639 }
640 netmask->s_addr = htonl(~((1 << (32 - prefix)) - 1));
641 if ((network->s_addr & netmask->s_addr) != network->s_addr) {
642 fprintf(stderr, "CIDR needs to be a network address like 10.0.2.0/24, "
643 "not like 10.0.2.100/24\n");
644 rc = -1;
645 goto finish;
646 }
647 finish:
648 regfree(&r);
649 return rc;
650 }
651
652 static int slirp4netns_config_from_cidr(struct slirp4netns_config *cfg,
653 const char *cidr)
654 {
655 int rc;
656 rc = parse_cidr(&cfg->vnetwork, &cfg->vnetmask, cidr);
657 if (rc < 0) {
658 goto finish;
659 }
660 cfg->vhost.s_addr =
661 htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_VHOST_OFFSET);
662 cfg->vdhcp_start.s_addr =
663 htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_VDHCPSTART_OFFSET);
664 cfg->vnameserver.s_addr =
665 htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_VNAMESERVER_OFFSET);
666 cfg->recommended_vguest.s_addr =
667 htonl(ntohl(cfg->vnetwork.s_addr) + DEFAULT_RECOMMENDED_VGUEST_OFFSET);
668 finish:
669 return rc;
670 }
671
672 static int slirp4netns_config_from_options(struct slirp4netns_config *cfg,
673 struct options *opt)
674 {
675 int rc = 0;
676 cfg->mtu = opt->mtu;
677 rc = slirp4netns_config_from_cidr(cfg, opt->cidr == NULL ? DEFAULT_CIDR :
678 opt->cidr);
679 if (rc < 0) {
680 goto finish;
681 }
682 cfg->enable_ipv6 = cfg->enable_ipv6;
683 cfg->disable_host_loopback = opt->disable_host_loopback;
684 cfg->enable_sandbox = opt->enable_sandbox;
685 cfg->enable_seccomp = opt->enable_seccomp;
686 finish:
687 return rc;
531688 }
532689
533690 int main(int argc, char *const argv[])
534691 {
535 int sv[2];
536 pid_t child_pid;
537 struct options options;
538 struct slirp4netns_config slirp4netns_config;
539 int exit_status = 0;
540
541 parse_args(argc, argv, &options);
542 if (slirp4netns_config_from_options(&slirp4netns_config, &options) < 0) {
543 exit_status = EXIT_FAILURE;
544 goto finish;
545 }
546 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) {
547 perror("socketpair");
548 exit_status = EXIT_FAILURE;
549 goto finish;
550 }
551 if ((child_pid = fork()) < 0) {
552 perror("fork");
553 exit_status = EXIT_FAILURE;
554 goto finish;
555 }
556 if (child_pid == 0) {
557 if (child(sv[1], options.target_pid, options.do_config_network, options.tapname, options.ready_fd,
558 &slirp4netns_config) < 0) {
559 exit_status = EXIT_FAILURE;
560 goto finish;
561 }
562 } else {
563 int child_wstatus, child_status;
564 waitpid(child_pid, &child_wstatus, 0);
565 if (!WIFEXITED(child_wstatus)) {
566 fprintf(stderr, "child failed\n");
567 exit_status = EXIT_FAILURE;
568 goto finish;
569 }
570 child_status = WEXITSTATUS(child_wstatus);
571 if (child_status != 0) {
572 fprintf(stderr, "child failed(%d)\n", child_status);
573 exit_status = child_status;
574 goto finish;
575 }
576 if (parent(sv[0], options.exit_fd, options.api_socket, &slirp4netns_config) < 0) {
577 fprintf(stderr, "parent failed\n");
578 exit_status = EXIT_FAILURE;
579 goto finish;
580 }
581 }
582 finish:
583 options_destroy(&options);
584 exit(exit_status);
585 return 0;
586 }
692 int sv[2];
693 pid_t child_pid;
694 struct options options;
695 struct slirp4netns_config slirp4netns_config;
696 int exit_status = 0;
697
698 parse_args(argc, argv, &options);
699 if (slirp4netns_config_from_options(&slirp4netns_config, &options) < 0) {
700 exit_status = EXIT_FAILURE;
701 goto finish;
702 }
703 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) {
704 perror("socketpair");
705 exit_status = EXIT_FAILURE;
706 goto finish;
707 }
708 if ((child_pid = fork()) < 0) {
709 perror("fork");
710 exit_status = EXIT_FAILURE;
711 goto finish;
712 }
713 if (child_pid == 0) {
714 if (child(sv[1], options.target_pid, options.do_config_network,
715 options.tapname, options.netns_path, options.userns_path,
716 &slirp4netns_config) < 0) {
717 exit_status = EXIT_FAILURE;
718 goto finish;
719 }
720 } else {
721 int ret, child_wstatus, child_status;
722 do
723 ret = waitpid(child_pid, &child_wstatus, 0);
724 while (ret < 0 && errno == EINTR);
725 if (ret < 0) {
726 perror("waitpid");
727 exit_status = EXIT_FAILURE;
728 goto finish;
729 }
730 if (!WIFEXITED(child_wstatus)) {
731 fprintf(stderr, "child failed(wstatus=%d, !WIFEXITED)\n",
732 child_wstatus);
733 exit_status = EXIT_FAILURE;
734 goto finish;
735 }
736 child_status = WEXITSTATUS(child_wstatus);
737 if (child_status != 0) {
738 fprintf(stderr, "child failed(%d)\n", child_status);
739 exit_status = child_status;
740 goto finish;
741 }
742 if (parent(sv[0], options.ready_fd, options.exit_fd, options.api_socket,
743 &slirp4netns_config, options.target_pid) < 0) {
744 fprintf(stderr, "parent failed\n");
745 exit_status = EXIT_FAILURE;
746 goto finish;
747 }
748 }
749 finish:
750 options_destroy(&options);
751 exit(exit_status);
752 return 0;
753 }
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
1 #define _GNU_SOURCE
2 #include <errno.h>
3 #include <sched.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/prctl.h>
9 #include <sys/mount.h>
10 #include <sys/syscall.h>
11 #include <sys/capability.h>
12 #include <sys/stat.h>
13
14 #include <glib.h>
15
16 static int add_mount(const char *from, const char *to)
17 {
18 int ret;
19
20 ret = mount("", from, "", MS_SLAVE | MS_REC, NULL);
21 if (ret < 0 && errno != EINVAL) {
22 fprintf(stderr, "cannot make mount propagation slave %s\n", from);
23 return ret;
24 }
25 ret = mount(from, to, "",
26 MS_BIND | MS_REC | MS_SLAVE | MS_NOSUID | MS_NODEV | MS_NOEXEC,
27 NULL);
28 if (ret < 0) {
29 fprintf(stderr, "cannot bind mount %s to %s\n", from, to);
30 return ret;
31 }
32 ret = mount("", to, "", MS_SLAVE | MS_REC, NULL);
33 if (ret < 0) {
34 fprintf(stderr, "cannot make mount propagation slave %s\n", to);
35 return ret;
36 }
37 ret = mount(from, to, "",
38 MS_REMOUNT | MS_BIND | MS_RDONLY | MS_NOSUID | MS_NODEV |
39 MS_NOEXEC,
40 NULL);
41 if (ret < 0) {
42 fprintf(stderr, "cannot remount ro %s\n", to);
43 return ret;
44 }
45 return 0;
46 }
47
48 /* Warn (not error) if /etc/resolv.conf is a symlink to a file outside /etc or
49 * /run. */
50 static void validate_etc_resolv_conf()
51 {
52 char *p = realpath("/etc/resolv.conf", NULL);
53 if (p == NULL) {
54 return;
55 }
56 if (!g_str_has_prefix(p, "/etc") && !g_str_has_prefix(p, "/run")) {
57 fprintf(stderr,
58 "sandbox: /etc/resolv.conf (-> %s) seems a symlink to a file "
59 "outside {/etc, /run}. DNS will not work.\n",
60 p);
61 }
62 free(p);
63 }
64
65 /* lock down the process doing the following:
66 - create a new mount namespace
67 - bind mount /etc and /run from the host
68 - pivot_root in the new tmpfs.
69 - drop all capabilities.
70 */
71 int create_sandbox()
72 {
73 int ret, i;
74 struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 };
75 struct __user_cap_data_struct data[2] = { { 0 } };
76
77 validate_etc_resolv_conf();
78
79 ret = unshare(CLONE_NEWNS);
80 if (ret < 0) {
81 fprintf(stderr, "cannot unshare new mount namespace\n");
82 return ret;
83 }
84 ret = mount("", "/", "", MS_PRIVATE, NULL);
85 if (ret < 0) {
86 fprintf(stderr, "cannot remount / private\n");
87 return ret;
88 }
89
90 ret = mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC,
91 "size=1k");
92 if (ret < 0) {
93 fprintf(stderr, "cannot mount tmpfs on /tmp\n");
94 return ret;
95 }
96
97 ret = mkdir("/tmp/etc", 0755);
98 if (ret < 0) {
99 fprintf(stderr, "cannot mkdir /etc\n");
100 return ret;
101 }
102
103 ret = mkdir("/tmp/old", 0755);
104 if (ret < 0) {
105 fprintf(stderr, "cannot mkdir /old\n");
106 return ret;
107 }
108
109 ret = mkdir("/tmp/run", 0755);
110 if (ret < 0) {
111 fprintf(stderr, "cannot mkdir /run\n");
112 return ret;
113 }
114
115 ret = add_mount("/etc", "/tmp/etc");
116 if (ret < 0) {
117 return ret;
118 }
119
120 ret = add_mount("/run", "/tmp/run");
121 if (ret < 0) {
122 return ret;
123 }
124
125 ret = chdir("/tmp");
126 if (ret < 0) {
127 fprintf(stderr, "cannot chdir to /tmp\n");
128 return ret;
129 }
130
131 ret = syscall(__NR_pivot_root, ".", "old");
132 if (ret < 0) {
133 fprintf(stderr, "cannot pivot_root to /tmp\n");
134 return ret;
135 }
136
137 ret = chdir("/");
138 if (ret < 0) {
139 fprintf(stderr, "cannot chdir to /\n");
140 return ret;
141 }
142
143 ret = umount2("/old", MNT_DETACH);
144 if (ret < 0) {
145 fprintf(stderr, "cannot umount /old\n");
146 return ret;
147 }
148
149 ret = rmdir("/old");
150 if (ret < 0) {
151 fprintf(stderr, "cannot rmdir /old\n");
152 return ret;
153 }
154
155 ret = mount("tmpfs", "/", "tmpfs", MS_REMOUNT | MS_RDONLY, "size=0k");
156 if (ret < 0) {
157 fprintf(stderr, "cannot remount / as read-only\n");
158 /* error is negligible (#163) */
159 }
160
161 ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
162 if (ret < 0) {
163 fprintf(stderr, "prctl(PR_SET_NO_NEW_PRIVS)\n");
164 return ret;
165 }
166
167 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
168 if (ret < 0) {
169 fprintf(stderr, "prctl(PR_CAP_AMBIENT_CLEAR_ALL)\n");
170 return ret;
171 }
172 for (i = 0;; i++) {
173 if (i == CAP_NET_BIND_SERVICE)
174 continue;
175 ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
176 if (ret < 0) {
177 if (errno == EINVAL)
178 break;
179 fprintf(stderr, "prctl(PR_CAPBSET_DROP)\n");
180 return ret;
181 }
182 }
183
184 memset(&data, 0, sizeof(data));
185 data[0].effective |= 1 << CAP_NET_BIND_SERVICE;
186 data[0].permitted |= 1 << CAP_NET_BIND_SERVICE;
187 data[0].inheritable |= 1 << CAP_NET_BIND_SERVICE;
188 ret = capset(&hdr, data);
189 if (ret < 0) {
190 fprintf(stderr, "capset(0)\n");
191 return ret;
192 }
193
194 return 0;
195 }
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
1 #ifndef SLIRP4NETNS_SANDBOX_H
2 # define SLIRP4NETNS_SANDBOX_H
3 int create_sandbox();
4 #endif
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <seccomp.h>
4
5 int enable_seccomp()
6 {
7 int rc = -1;
8 /* Allow everything by default and block dangerous syscalls explicitly,
9 * as it is hard to find the correct set of required syscalls */
10 scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
11 if (ctx == NULL)
12 goto ret;
13 printf("seccomp: The following syscalls will be blocked by seccomp:");
14 #ifdef SCMP_ACT_KILL_PROCESS
15 #define BLOCK_ACTION SCMP_ACT_KILL_PROCESS
16 #else
17 #define BLOCK_ACTION SCMP_ACT_KILL
18 #endif
19 #define BLOCK(x) \
20 { \
21 rc = seccomp_rule_add(ctx, BLOCK_ACTION, SCMP_SYS(x), 0); \
22 if (rc < 0) \
23 goto ret; \
24 printf(" %s", #x); \
25 }
26 BLOCK(execve);
27 #ifdef __NR_execveat
28 BLOCK(execveat);
29 #else
30 fprintf(stderr,
31 "seccomp: can't block execevat because __NR_execveat was not "
32 "defined in the build environment\n");
33 #endif
34 /* ideally we should also block open() and openat() but required for
35 * resolv.conf */
36 BLOCK(open_by_handle_at);
37 BLOCK(ptrace);
38 BLOCK(prctl);
39 BLOCK(process_vm_readv);
40 BLOCK(process_vm_writev);
41 BLOCK(mount);
42 BLOCK(name_to_handle_at);
43 BLOCK(setns);
44 BLOCK(umount);
45 BLOCK(umount2);
46 BLOCK(unshare);
47 #undef BLOCK
48 #undef BLOCK_ACTION
49 printf(".\n");
50 rc = seccomp_load(ctx);
51 ret:
52 seccomp_release(ctx);
53 return rc;
54 }
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
1 #ifndef SLIRP4NETNS_SECCOMPFILTER_H
2 # define SLIRP4NETNS_SECCOMPFILTER_H
3 int enable_seccomp();
4 #endif
00 .nh
1 .TH SLIRP4NETNS 1 "July 2018" "Rootless Containers" "User Commands"
1 .TH SLIRP4NETNS 1 "March 2020" "Rootless Containers" "User Commands"
22
33 .SH NAME
44 .PP
77
88 .SH SYNOPSIS
99 .PP
10 slirp4netns [OPTION]... PID TAPNAME
10 slirp4netns [OPTION]... PID|PATH TAPNAME
1111
1212
1313 .SH DESCRIPTION
4242 .SH OPTIONS
4343 .PP
4444 \fB\-c\fP, \fB\-\-configure\fP
45 bring up the interface. IP will be set to 10.0.2.100 (network address + 100) by default. IPv6 will be set to a random address.
45 bring up the TAP interface. IP will be set to 10.0.2.100 (network address + 100) by default. IPv6 will be set to a random address.
46 Starting with v0.4.0, the loopback interface (\fBlo\fP) is brought up as well.
4647
4748 .PP
4849 \fB\-e\fP, \fB\-\-exit\-fd=FD\fP
4950 specify the FD for terminating slirp4netns.
51 When the FD is specified, slirp4netns exits when a \fBpoll(2)\fP event happens on the FD.
5052
5153 .PP
5254 \fB\-r\fP, \fB\-\-ready\-fd=FD\fP
53 specify the FD to write to when the network is configured.
54
55 .PP
56 \fB\-m\fP, \fB\-\-mtu=MTU\fP
55 specify the FD to write to when the initialization steps are finished.
56 When the FD is specified, slirp4netns writes \fB"1"\fP to the FD and close the FD.
57 Prior to v0.4.0, the FD was written after the network configuration (\fB\-c\fP)
58 but before the API socket configuration (\fB\-a\fP).
59
60 .PP
61 \fB\-m\fP, \fB\-\-mtu=MTU\fP (since v0.2.0)
5762 specify MTU (max=65521).
63
64 .PP
65 \fB\-6\fP, \fB\-\-enable\-ipv6\fP (since v0.2.0, EXPERIMENTAL)
66 enable IPv6
67
68 .PP
69 \fB\-a\fP, \fB\-\-api\-socket\fP (since v0.3.0)
70 API socket path
5871
5972 .PP
6073 \fB\-\-cidr\fP (since v0.3.0)
6578 prohibit connecting to 127.0.0.1:* on the host namespace
6679
6780 .PP
68 \fB\-a\fP, \fB\-\-api\-socket\fP (since v0.3.0)
69 API socket path
70
71 .PP
72 \fB\-6\fP, \fB\-\-enable\-ipv6\fP
73 enable IPv6 (experimental).
74
75 .PP
76 \fB\-h\fP, \fB\-\-help\fP
81 \fB\-\-netns\-type=TYPE\fP (since v0.4.0)
82 specify network namespace type ([path|pid], default=pid)
83
84 .PP
85 \fB\-\-userns\-path=PATH\fP (since v0.4.0)
86 specify user namespace path
87
88 .PP
89 \fB\-\-enable\-sandbox\fP (since v0.4.0)
90 enter the user namespace and create a new mount namespace where only /etc and
91 /run are mounted from the host.
92
93 .PP
94 Requires \fB/etc/resolv.conf\fP not to be a symlink to a file outside /etc and /run.
95
96 .PP
97 When running as the root, the process does not enter the user namespace but all
98 the capabilities except \fB\fCCAP\_NET\_BIND\_SERVICE\fR are dropped.
99
100 .PP
101 \fB\-\-enable\-seccomp\fP (since v0.4.0, EXPERIMENTAL)
102 enable \fBseccomp(2)\fP to limit syscalls.
103 Typically used in conjunction with \fB\-\-enable\-sandbox\fP\&.
104
105 .PP
106 \fB\-h\fP, \fB\-\-help\fP (since v0.2.0)
77107 show help and exit
78108
79109 .PP
80 \fB\-v\fP, \fB\-\-version\fP
110 \fB\-v\fP, \fB\-\-version\fP (since v0.2.0)
81111 show version and exit
82112
83113
267297
268298 .RS
269299 .IP \(bu 2
270 Client needs to \fBshutdown\fP the socket with \fBSHUT\_WR\fP after sending every request.
300 Client needs to \fBshutdown(2)\fP the socket with \fBSHUT\_WR\fP after sending every request.
271301 i.e. No support for keep\-alive and timeout.
272302 .IP \(bu 2
273303 slirp4netns "stops the world" during processing API requests.
274304 .IP \(bu 2
275 A request must be less than 4095 bytes.
305 A request must be less than 4096 bytes.
276306 .IP \(bu 2
277307 JSON responses may contain \fBerror\fP instead of \fBreturn\fP\&.
278308
279309 .RE
280310
281311
312 .SH DEFINED NAMESPACE PATHS
313 .PP
314 A user can define a network namespace path as opposed to the default process ID:
315
316 .PP
317 .RS
318
319 .nf
320 $ slirp4netns \-\-netns\-type=path ... /path/to/netns tap0
321
322 .fi
323 .RE
324
325 .PP
326 Currently, the \fBnetns\-type=TYPE\fP argument supports \fBpath\fP or \fBpid\fP args with the default being \fBpid\fP\&.
327
328 .PP
329 Additionally, a \fB\-\-userns\-path=PATH\fP argument can be included to override any user namespace path defaults
330
331 .PP
332 .RS
333
334 .nf
335 $ slirp4netns \-\-netns\-type=path \-\-userns\-path=/path/to/userns /path/to/netns tap0
336
337 .fi
338 .RE
339
340
341 .SH BUGS
342 .PP
343 Kernel 4.20 bumped up the default value of \fB/proc/sys/net/ipv4/tcp\_rmem\fP from 87380 to 131072.
344 This is known to slow down slirp4netns port forwarding: \fBhttps://github.com/rootless\-containers/slirp4netns/issues/128\fP\&.
345
346 .PP
347 As a workaround, you can adjust the value of \fB/proc/sys/net/ipv4/tcp\_rmem\fP inside the namespace.
348 No real root privilege is needed to modify the file since kernel 4.15.
349
350 .PP
351 .RS
352
353 .nf
354 unshared$ c=$(cat /proc/sys/net/ipv4/tcp\_rmem); echo $c | sed \-e s/131072/87380/g > /proc/sys/net/ipv4/tcp\_rmem
355
356 .fi
357 .RE
358
359
282360 .SH SEE ALSO
283361 .PP
284362 \fBnetwork\_namespaces\fP(7), \fBuser\_namespaces\fP(7), \fBveth\fP(4)
286364
287365 .SH AVAILABILITY
288366 .PP
289 The slirp4netns command is available from \fBhttps://github.com/rootless\-containers/slirp4netns\fP under GNU GENERAL PUBLIC LICENSE Version 2.
367 The slirp4netns command is available from \fBhttps://github.com/rootless\-containers/slirp4netns\fP under GNU GENERAL PUBLIC LICENSE Version 2 (or later).
0 SLIRP4NETNS 1 "July 2018" "Rootless Containers" "User Commands"
0 SLIRP4NETNS 1 "March 2020" "Rootless Containers" "User Commands"
11 ==================================================
22
33 # NAME
66
77 # SYNOPSIS
88
9 slirp4netns [OPTION]... PID TAPNAME
9 slirp4netns [OPTION]... PID|PATH TAPNAME
1010
1111 # DESCRIPTION
1212
2727 # OPTIONS
2828
2929 **-c**, **--configure**
30 bring up the interface. IP will be set to 10.0.2.100 (network address + 100) by default. IPv6 will be set to a random address.
30 bring up the TAP interface. IP will be set to 10.0.2.100 (network address + 100) by default. IPv6 will be set to a random address.
31 Starting with v0.4.0, the loopback interface (**lo**) is brought up as well.
3132
3233 **-e**, **--exit-fd=FD**
3334 specify the FD for terminating slirp4netns.
35 When the FD is specified, slirp4netns exits when a **poll(2)** event happens on the FD.
3436
3537 **-r**, **--ready-fd=FD**
36 specify the FD to write to when the network is configured.
37
38 **-m**, **--mtu=MTU**
38 specify the FD to write to when the initialization steps are finished.
39 When the FD is specified, slirp4netns writes **"1"** to the FD and close the FD.
40 Prior to v0.4.0, the FD was written after the network configuration (**-c**)
41 but before the API socket configuration (**-a**).
42
43 **-m**, **--mtu=MTU** (since v0.2.0)
3944 specify MTU (max=65521).
45
46 **-6**, **--enable-ipv6** (since v0.2.0, EXPERIMENTAL)
47 enable IPv6
48
49 **-a**, **--api-socket** (since v0.3.0)
50 API socket path
4051
4152 **--cidr** (since v0.3.0)
4253 specify CIDR, e.g. 10.0.2.0/24
4455 **--disable-host-loopback** (since v0.3.0)
4556 prohibit connecting to 127.0.0.1:\* on the host namespace
4657
47 **-a**, **--api-socket** (since v0.3.0)
48 API socket path
49
50 **-6**, **--enable-ipv6**
51 enable IPv6 (experimental).
52
53 **-h**, **--help**
58 **--netns-type=TYPE** (since v0.4.0)
59 specify network namespace type ([path|pid], default=pid)
60
61 **--userns-path=PATH** (since v0.4.0)
62 specify user namespace path
63
64 **--enable-sandbox** (since v0.4.0)
65 enter the user namespace and create a new mount namespace where only /etc and
66 /run are mounted from the host.
67
68 Requires **/etc/resolv.conf** not to be a symlink to a file outside /etc and /run.
69
70 When running as the root, the process does not enter the user namespace but all
71 the capabilities except `CAP_NET_BIND_SERVICE` are dropped.
72
73 **--enable-seccomp** (since v0.4.0, EXPERIMENTAL)
74 enable **seccomp(2)** to limit syscalls.
75 Typically used in conjunction with **--enable-sandbox**.
76
77 **-h**, **--help** (since v0.2.0)
5478 show help and exit
5579
56 **-v**, **--version**
80 **-v**, **--version** (since v0.2.0)
5781 show version and exit
5882
5983 # EXAMPLE
171195
172196 Remarks:
173197
174 * Client needs to **shutdown** the socket with **SHUT_WR** after sending every request.
198 * Client needs to **shutdown(2)** the socket with **SHUT_WR** after sending every request.
175199 i.e. No support for keep-alive and timeout.
176200 * slirp4netns "stops the world" during processing API requests.
177 * A request must be less than 4095 bytes.
201 * A request must be less than 4096 bytes.
178202 * JSON responses may contain **error** instead of **return**.
179203
204 # DEFINED NAMESPACE PATHS
205 A user can define a network namespace path as opposed to the default process ID:
206
207 ```console
208 $ slirp4netns --netns-type=path ... /path/to/netns tap0
209 ```
210 Currently, the **netns-type=TYPE** argument supports **path** or **pid** args with the default being **pid**.
211
212 Additionally, a **--userns-path=PATH** argument can be included to override any user namespace path defaults
213 ```console
214 $ slirp4netns --netns-type=path --userns-path=/path/to/userns /path/to/netns tap0
215 ```
216
217 # BUGS
218
219 Kernel 4.20 bumped up the default value of **/proc/sys/net/ipv4/tcp_rmem** from 87380 to 131072.
220 This is known to slow down slirp4netns port forwarding: **https://github.com/rootless-containers/slirp4netns/issues/128**.
221
222 As a workaround, you can adjust the value of **/proc/sys/net/ipv4/tcp_rmem** inside the namespace.
223 No real root privilege is needed to modify the file since kernel 4.15.
224
225 ```console
226 unshared$ c=$(cat /proc/sys/net/ipv4/tcp_rmem); echo $c | sed -e s/131072/87380/g > /proc/sys/net/ipv4/tcp_rmem
227 ```
228
180229 # SEE ALSO
181230
182231 **network_namespaces**(7), **user_namespaces**(7), **veth**(4)
183232
184233 # AVAILABILITY
185234
186 The slirp4netns command is available from **https://github.com/rootless-containers/slirp4netns** under GNU GENERAL PUBLIC LICENSE Version 2.
235 The slirp4netns command is available from **https://github.com/rootless-containers/slirp4netns** under GNU GENERAL PUBLIC LICENSE Version 2 (or later).
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
01 #define _GNU_SOURCE
12 #include <errno.h>
23 #include <signal.h>
56 #include <unistd.h>
67
78 #include <glib.h>
8
9 #include "vendor/libslirp/src/libslirp.h"
9 #include <libslirp.h>
10
1011 #include "api.h"
12 #include "sandbox.h"
13 #include "seccompfilter.h"
1114 #include "slirp4netns.h"
1215
1316 /* opaque for SlirpCb */
1417 struct libslirp_data {
15 int tapfd;
16 GSList *timers;
18 int tapfd;
19 GSList *timers;
1720 };
1821
1922 /* implements SlirpCb.send_packet */
20 static ssize_t libslirp_send_packet(const void *pkt, size_t pkt_len, void *opaque)
21 {
22 struct libslirp_data *data = (struct libslirp_data *)opaque;
23 return write(data->tapfd, pkt, pkt_len);
23 static ssize_t libslirp_send_packet(const void *pkt, size_t pkt_len,
24 void *opaque)
25 {
26 struct libslirp_data *data = (struct libslirp_data *)opaque;
27 return write(data->tapfd, pkt, pkt_len);
2428 }
2529
2630 /* implements SlirpCb.guest_error */
2731 static void libslirp_guest_error(const char *msg, void *opaque)
2832 {
29 fprintf(stderr, "libslirp: %s\n", msg);
33 fprintf(stderr, "libslirp: %s\n", msg);
3034 }
3135
3236 /* implements SlirpCb.clock_get_ns */
3337 static int64_t libslirp_clock_get_ns(void *opaque)
3438 {
35 struct timespec ts;
36 clock_gettime(CLOCK_MONOTONIC, &ts);
37 return ts.tv_sec * 1000000000LL + ts.tv_nsec;
39 struct timespec ts;
40 clock_gettime(CLOCK_MONOTONIC, &ts);
41 return ts.tv_sec * 1000000000LL + ts.tv_nsec;
3842 }
3943
4044 /* timer for SlirpCb */
4145 struct timer {
42 SlirpTimerCb cb;
43 void *cb_opaque;
44 int64_t expire_timer_msec;
46 SlirpTimerCb cb;
47 void *cb_opaque;
48 int64_t expire_timer_msec;
4549 };
4650
4751 /* implements SlirpCb.timer_new */
4852 static void *libslirp_timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque)
4953 {
50 struct libslirp_data *data = (struct libslirp_data *)opaque;
51 struct timer *t = g_malloc0(sizeof(*t));
52 t->cb = cb;
53 t->cb_opaque = cb_opaque;
54 t->expire_timer_msec = -1;
55 data->timers = g_slist_append(data->timers, t);
56 return t;
54 struct libslirp_data *data = (struct libslirp_data *)opaque;
55 struct timer *t = g_malloc0(sizeof(*t));
56 t->cb = cb;
57 t->cb_opaque = cb_opaque;
58 t->expire_timer_msec = -1;
59 data->timers = g_slist_append(data->timers, t);
60 return t;
5761 }
5862
5963 /* implements SlirpCb.timer_free */
6064 static void libslirp_timer_free(void *timer, void *opaque)
6165 {
62 struct libslirp_data *data = (struct libslirp_data *)opaque;
63 data->timers = g_slist_remove(data->timers, timer);
64 g_free(timer);
66 struct libslirp_data *data = (struct libslirp_data *)opaque;
67 data->timers = g_slist_remove(data->timers, timer);
68 g_free(timer);
6569 }
6670
6771 /* implements SlirpCb.timer_mod */
68 static void libslirp_timer_mod(void *timer, int64_t expire_timer_msec, void *opaque)
69 {
70 struct timer *t = (struct timer *)timer;
71 t->expire_timer_msec = expire_timer_msec;
72 static void libslirp_timer_mod(void *timer, int64_t expire_timer_msec,
73 void *opaque)
74 {
75 struct timer *t = (struct timer *)timer;
76 t->expire_timer_msec = expire_timer_msec;
7277 }
7378
7479 /* implements SlirpCb.register_poll_fd */
7580 static void libslirp_register_poll_fd(int fd, void *opaque)
7681 {
77 /*
78 * NOP
79 *
80 * This is NOP on QEMU upstream on Linux as well, see:
81 * * qemu/net/slirp.c: net_slirp_register_poll_fd (calls qemu_fd_register)
82 * * qemu/stubs/fd-register.c: qemu_fd_register (NOP on Linux)
83 *
84 * See also:
85 * * qemu/util/main-loop.c: qemu_fd_register (Win32 only)
86 */
82 /*
83 * NOP
84 *
85 * This is NOP on QEMU@4c76137484878f42a2ce1ae1b888b6a7f66b4053 on Linux as
86 * well, see:
87 * * qemu/net/slirp.c: net_slirp_register_poll_fd (calls
88 * qemu_fd_register)
89 * * qemu/stubs/fd-register.c: qemu_fd_register (NOP on Linux)
90 *
91 * See also:
92 * * qemu/util/main-loop.c: qemu_fd_register (Win32 only)
93 */
8794 }
8895
8996 /* implements SlirpCb.unregister_poll_fd */
9097 static void libslirp_unregister_poll_fd(int fd, void *opaque)
9198 {
92 /*
93 * NOP
94 *
95 * This is NOP on QEMU upstream as well, see:
96 * * qemu/net/slirp.c: net_slirp_unregister_poll_fd (NOP)
97 */
99 /*
100 * NOP
101 *
102 * This is NOP on QEMU@4c76137484878f42a2ce1ae1b888b6a7f66b4053 as well,
103 * see:
104 * * qemu/net/slirp.c: net_slirp_unregister_poll_fd (NOP)
105 */
98106 }
99107
100108 /* implements SlirpCb.notify */
101109 static void libslirp_notify(void *opaque)
102110 {
103 /*
104 * NOP
105 *
106 * This can be NOP on QEMU upstream as well, see:
107 * * qemu/net/slirp.c: net_slirp_notify (calls qemu_notify_event)
108 * * qemu/stubs/notify-event.c: qemu_notify_event (NOP)
109 *
110 * See also:
111 * * qemu/util/main-loop.c: qemu_notify_event (NOP if !qemu_aio_context)
112 */
111 /*
112 * NOP
113 *
114 * This can be NOP on QEMU@4c76137484878f42a2ce1ae1b888b6a7f66b4053 as well,
115 * see:
116 * * qemu/net/slirp.c: net_slirp_notify (calls qemu_notify_event)
117 * * qemu/stubs/notify-event.c: qemu_notify_event (NOP)
118 *
119 * See also:
120 * * qemu/util/main-loop.c: qemu_notify_event (NOP if
121 * !qemu_aio_context)
122 */
113123 }
114124
115125 static int libslirp_poll_to_gio(int events)
116126 {
117 int ret = 0;
118 if (events & SLIRP_POLL_IN) {
119 ret |= G_IO_IN;
120 }
121 if (events & SLIRP_POLL_OUT) {
122 ret |= G_IO_OUT;
123 }
124 if (events & SLIRP_POLL_PRI) {
125 ret |= G_IO_PRI;
126 }
127 if (events & SLIRP_POLL_ERR) {
128 ret |= G_IO_ERR;
129 }
130 if (events & SLIRP_POLL_HUP) {
131 ret |= G_IO_HUP;
132 }
133 return ret;
127 int ret = 0;
128 if (events & SLIRP_POLL_IN) {
129 ret |= G_IO_IN;
130 }
131 if (events & SLIRP_POLL_OUT) {
132 ret |= G_IO_OUT;
133 }
134 if (events & SLIRP_POLL_PRI) {
135 ret |= G_IO_PRI;
136 }
137 if (events & SLIRP_POLL_ERR) {
138 ret |= G_IO_ERR;
139 }
140 if (events & SLIRP_POLL_HUP) {
141 ret |= G_IO_HUP;
142 }
143 return ret;
134144 }
135145
136146 /*
137147 * implements SlirpAddPollCb used in slirp_pollfds_fill.
138 * originally from qemu/net/slirp.c:net_slirp_add_poll
148 * originally from qemu/net/slirp.c:net_slirp_add_poll
149 * (4c76137484878f42a2ce1ae1b888b6a7f66b4053)
139150 */
140151 static int libslirp_add_poll(int fd, int events, void *opaque)
141152 {
142 GArray *pollfds = opaque;
143 GPollFD pfd = {
144 .fd = fd,
145 .events = libslirp_poll_to_gio(events),
146 };
147 int idx = pollfds->len;
148 g_array_append_val(pollfds, pfd);
149 return idx;
153 GArray *pollfds = opaque;
154 GPollFD pfd = {
155 .fd = fd,
156 .events = libslirp_poll_to_gio(events),
157 };
158 int idx = pollfds->len;
159 g_array_append_val(pollfds, pfd);
160 return idx;
150161 }
151162
152163 static int libslirp_gio_to_poll(int events)
153164 {
154 int ret = 0;
155 if (events & G_IO_IN) {
156 ret |= SLIRP_POLL_IN;
157 }
158 if (events & G_IO_OUT) {
159 ret |= SLIRP_POLL_OUT;
160 }
161 if (events & G_IO_PRI) {
162 ret |= SLIRP_POLL_PRI;
163 }
164 if (events & G_IO_ERR) {
165 ret |= SLIRP_POLL_ERR;
166 }
167 if (events & G_IO_HUP) {
168 ret |= SLIRP_POLL_HUP;
169 }
170 return ret;
165 int ret = 0;
166 if (events & G_IO_IN) {
167 ret |= SLIRP_POLL_IN;
168 }
169 if (events & G_IO_OUT) {
170 ret |= SLIRP_POLL_OUT;
171 }
172 if (events & G_IO_PRI) {
173 ret |= SLIRP_POLL_PRI;
174 }
175 if (events & G_IO_ERR) {
176 ret |= SLIRP_POLL_ERR;
177 }
178 if (events & G_IO_HUP) {
179 ret |= SLIRP_POLL_HUP;
180 }
181 return ret;
171182 }
172183
173184 /*
174185 * implements SlirpGetREventsCB used in slirp_pollfds_poll
175186 * originally from qemu/net/slirp.c:net_slirp_get_revents
187 * (4c76137484878f42a2ce1ae1b888b6a7f66b4053)
176188 */
177189 static int libslirp_get_revents(int idx, void *opaque)
178190 {
179 GArray *pollfds = opaque;
180 return libslirp_gio_to_poll(g_array_index(pollfds, GPollFD, idx).revents);
191 GArray *pollfds = opaque;
192 return libslirp_gio_to_poll(g_array_index(pollfds, GPollFD, idx).revents);
181193 }
182194
183195 /*
184196 * updates timeout_msec for data->timers
185 * originally from https://github.com/rd235/libslirp/blob/d2b7032e29f3ba98e17414b32c9effffc90f2bb0/src/qemu2libslirp.c#L66
197 * originally from
198 * https://github.com/rd235/libslirp/blob/d2b7032e29f3ba98e17414b32c9effffc90f2bb0/src/qemu2libslirp.c#L66
186199 */
187 static void update_ra_timeout(uint32_t * timeout_msec, struct libslirp_data *data)
188 {
189 int64_t now_msec = libslirp_clock_get_ns(data) / 1000000;
190 GSList *f;
191 for (f = data->timers; f != NULL; f = f->next) {
192 struct timer *t = f->data;
193 if (t->expire_timer_msec != -1) {
194 int64_t diff = t->expire_timer_msec - now_msec;
195 if (diff < 0)
196 diff = 0;
197 if (diff < *timeout_msec)
198 *timeout_msec = diff;
199 }
200 }
200 static void update_ra_timeout(uint32_t *timeout_msec,
201 struct libslirp_data *data)
202 {
203 int64_t now_msec = libslirp_clock_get_ns(data) / 1000000;
204 GSList *f;
205 for (f = data->timers; f != NULL; f = f->next) {
206 struct timer *t = f->data;
207 if (t->expire_timer_msec != -1) {
208 int64_t diff = t->expire_timer_msec - now_msec;
209 if (diff < 0)
210 diff = 0;
211 if (diff < *timeout_msec)
212 *timeout_msec = diff;
213 }
214 }
201215 }
202216
203217 /*
204218 * calls SlirpTimerCb if timed out
205 * originally from https://github.com/rd235/libslirp/blob/d2b7032e29f3ba98e17414b32c9effffc90f2bb0/src/qemu2libslirp.c#L78
219 * originally from
220 * https://github.com/rd235/libslirp/blob/d2b7032e29f3ba98e17414b32c9effffc90f2bb0/src/qemu2libslirp.c#L78
206221 */
207222 static void check_ra_timeout(struct libslirp_data *data)
208223 {
209 int64_t now_msec = libslirp_clock_get_ns(data) / 1000000;
210 GSList *f;
211 for (f = data->timers; f != NULL; f = f->next) {
212 struct timer *t = f->data;
213 if (t->expire_timer_msec != -1) {
214 int64_t diff = t->expire_timer_msec - now_msec;
215 if (diff <= 0) {
216 t->expire_timer_msec = -1;
217 t->cb(t->cb_opaque);
218 }
219 }
220 }
224 int64_t now_msec = libslirp_clock_get_ns(data) / 1000000;
225 GSList *f;
226 for (f = data->timers; f != NULL; f = f->next) {
227 struct timer *t = f->data;
228 if (t->expire_timer_msec != -1) {
229 int64_t diff = t->expire_timer_msec - now_msec;
230 if (diff <= 0) {
231 t->expire_timer_msec = -1;
232 t->cb(t->cb_opaque);
233 }
234 }
235 }
221236 }
222237
223238 static const SlirpCb libslirp_cb = {
224 .send_packet = libslirp_send_packet,
225 .guest_error = libslirp_guest_error,
226 .clock_get_ns = libslirp_clock_get_ns,
227 .timer_new = libslirp_timer_new,
228 .timer_free = libslirp_timer_free,
229 .timer_mod = libslirp_timer_mod,
230 .register_poll_fd = libslirp_register_poll_fd,
231 .unregister_poll_fd = libslirp_unregister_poll_fd,
232 .notify = libslirp_notify,
239 .send_packet = libslirp_send_packet,
240 .guest_error = libslirp_guest_error,
241 .clock_get_ns = libslirp_clock_get_ns,
242 .timer_new = libslirp_timer_new,
243 .timer_free = libslirp_timer_free,
244 .timer_mod = libslirp_timer_mod,
245 .register_poll_fd = libslirp_register_poll_fd,
246 .unregister_poll_fd = libslirp_unregister_poll_fd,
247 .notify = libslirp_notify,
233248 };
234249
235250 Slirp *create_slirp(void *opaque, struct slirp4netns_config *s4nn)
236251 {
237 Slirp *slirp = NULL;
238 SlirpConfig cfg;
239 memset(&cfg, 0, sizeof(cfg));
240 cfg.version = 1;
241 cfg.restricted = 0;
242 cfg.in_enabled = 1;
243 cfg.vnetwork = s4nn->vnetwork;
244 cfg.vnetmask = s4nn->vnetmask;
245 cfg.vhost = s4nn->vhost;
246 cfg.in6_enabled = (int)(s4nn->enable_ipv6);
247 inet_pton(AF_INET6, "fd00::", &cfg.vprefix_addr6);
248 cfg.vprefix_len = 64;
249 inet_pton(AF_INET6, "fd00::2", &cfg.vhost6);
250 cfg.vhostname = NULL;
251 cfg.tftp_server_name = NULL;
252 cfg.tftp_path = NULL;
253 cfg.bootfile = NULL;
254 cfg.vdhcp_start = s4nn->vdhcp_start;
255 cfg.vnameserver = s4nn->vnameserver;
256 inet_pton(AF_INET6, "fd00::3", &cfg.vnameserver6);
257 cfg.vdnssearch = NULL;
258 cfg.vdomainname = NULL;
259 cfg.if_mtu = s4nn->mtu;
260 cfg.if_mru = s4nn->mtu;
261 cfg.disable_host_loopback = s4nn->disable_host_loopback;
262 slirp = slirp_new(&cfg, &libslirp_cb, opaque);
263 if (slirp == NULL) {
264 fprintf(stderr, "slirp_initx failed\n");
265 }
266 return slirp;
252 Slirp *slirp = NULL;
253 SlirpConfig cfg;
254 memset(&cfg, 0, sizeof(cfg));
255 cfg.version = 1;
256 cfg.restricted = 0;
257 cfg.in_enabled = 1;
258 cfg.vnetwork = s4nn->vnetwork;
259 cfg.vnetmask = s4nn->vnetmask;
260 cfg.vhost = s4nn->vhost;
261 cfg.in6_enabled = (int)(s4nn->enable_ipv6);
262 inet_pton(AF_INET6, "fd00::", &cfg.vprefix_addr6);
263 cfg.vprefix_len = 64;
264 inet_pton(AF_INET6, "fd00::2", &cfg.vhost6);
265 cfg.vhostname = NULL;
266 cfg.tftp_server_name = NULL;
267 cfg.tftp_path = NULL;
268 cfg.bootfile = NULL;
269 cfg.vdhcp_start = s4nn->vdhcp_start;
270 cfg.vnameserver = s4nn->vnameserver;
271 inet_pton(AF_INET6, "fd00::3", &cfg.vnameserver6);
272 cfg.vdnssearch = NULL;
273 cfg.vdomainname = NULL;
274 cfg.if_mtu = s4nn->mtu;
275 cfg.if_mru = s4nn->mtu;
276 cfg.disable_host_loopback = s4nn->disable_host_loopback;
277 slirp = slirp_new(&cfg, &libslirp_cb, opaque);
278 if (slirp == NULL) {
279 fprintf(stderr, "slirp_new failed\n");
280 }
281 return slirp;
267282 }
268283
269284 #define ETH_BUF_SIZE (65536)
270285
271 int do_slirp(int tapfd, int exitfd, const char *api_socket, struct slirp4netns_config *cfg)
272 {
273 int ret = -1;
274 Slirp *slirp = NULL;
275 uint8_t *buf = NULL;
276 struct libslirp_data opaque = {.tapfd = tapfd,.timers = NULL };
277 int apifd = -1;
278 struct api_ctx *apictx = NULL;
279 GArray *pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
280 int pollfds_exitfd_idx = -1;
281 int pollfds_apifd_idx = -1;
282 size_t n_fds = 1;
283 GPollFD tap_pollfd = {.fd = tapfd,.events = G_IO_IN | G_IO_HUP,.revents = 0
284 };
285 GPollFD exit_pollfd = {.fd = exitfd,.events = G_IO_HUP,.revents = 0
286 };
287 GPollFD api_pollfd = {.fd = -1,.events = G_IO_IN | G_IO_HUP,.revents = 0
288 };
289
290 slirp = create_slirp((void *)&opaque, cfg);
291 if (slirp == NULL) {
292 fprintf(stderr, "create_slirp failed\n");
293 goto err;
294 }
295 buf = malloc(ETH_BUF_SIZE);
296 if (buf == NULL) {
297 goto err;
298 }
299 g_array_append_val(pollfds, tap_pollfd);
300 if (exitfd >= 0) {
301 n_fds++;
302 g_array_append_val(pollfds, exit_pollfd);
303 pollfds_exitfd_idx = n_fds - 1;
304 }
305 if (api_socket != NULL) {
306 if ((apifd = api_bindlisten(api_socket)) < 0) {
307 goto err;
308 }
309 if ((apictx = api_ctx_alloc(cfg)) == NULL) {
310 fprintf(stderr, "api_ctx_alloc failed\n");
311 goto err;
312 }
313 api_pollfd.fd = apifd;
314 n_fds++;
315 g_array_append_val(pollfds, api_pollfd);
316 pollfds_apifd_idx = n_fds - 1;
317 }
318 signal(SIGPIPE, SIG_IGN);
319 while (1) {
320 int pollout;
321 GPollFD *pollfds_data;
322 uint32_t timeout = -1; /* msec */
323 g_array_set_size(pollfds, n_fds);
324 slirp_pollfds_fill(slirp, &timeout, libslirp_add_poll, pollfds);
325 update_ra_timeout(&timeout, &opaque);
326 pollfds_data = (GPollFD *)pollfds->data;
327 do {
328 pollout = g_poll(pollfds_data, pollfds->len, timeout);
329 } while (pollout < 0 && errno == EINTR);
330 if (pollout < 0) {
331 goto err;
332 }
333
334 if (pollfds_data[0].revents) {
335 ssize_t rc = read(tapfd, buf, ETH_BUF_SIZE);
336 if (rc < 0) {
337 perror("do_slirp: read");
338 goto after_slirp_input;
339 }
340 slirp_input(slirp, buf, (int)rc);
341 after_slirp_input:
342 pollout = -1;
343 }
344
345 /* The exitfd is closed. */
346 if (pollfds_exitfd_idx >= 0 && pollfds_data[pollfds_exitfd_idx].revents) {
347 fprintf(stderr, "exitfd event\n");
348 goto success;
349 }
350
351 if (pollfds_apifd_idx >= 0 && pollfds_data[pollfds_apifd_idx].revents) {
352 int rc;
353 fprintf(stderr, "apifd event\n");
354 if ((rc = api_handler(slirp, apifd, apictx)) < 0) {
355 fprintf(stderr, "api_handler: rc=%d\n", rc);
356 }
357 }
358
359 slirp_pollfds_poll(slirp, (pollout <= 0), libslirp_get_revents, pollfds);
360 check_ra_timeout(&opaque);
361 }
362 success:
363 ret = 0;
364 err:
365 fprintf(stderr, "do_slirp is exiting\n");
366 if (buf != NULL) {
367 free(buf);
368 }
369 if (apictx != NULL) {
370 api_ctx_free(apictx);
371 unlink(api_socket);
372 }
373 g_array_free(pollfds, TRUE);
374 return ret;
375 }
286 int do_slirp(int tapfd, int readyfd, int exitfd, const char *api_socket,
287 struct slirp4netns_config *cfg)
288 {
289 int ret = -1;
290 Slirp *slirp = NULL;
291 uint8_t *buf = NULL;
292 struct libslirp_data opaque = { .tapfd = tapfd, .timers = NULL };
293 int apifd = -1;
294 struct api_ctx *apictx = NULL;
295 GArray *pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
296 int pollfds_exitfd_idx = -1;
297 int pollfds_apifd_idx = -1;
298 size_t n_fds = 1;
299 GPollFD tap_pollfd = { .fd = tapfd,
300 .events = G_IO_IN | G_IO_HUP,
301 .revents = 0 };
302 GPollFD exit_pollfd = { .fd = exitfd, .events = G_IO_HUP, .revents = 0 };
303 GPollFD api_pollfd = { .fd = -1,
304 .events = G_IO_IN | G_IO_HUP,
305 .revents = 0 };
306
307 slirp = create_slirp((void *)&opaque, cfg);
308 if (slirp == NULL) {
309 fprintf(stderr, "create_slirp failed\n");
310 goto err;
311 }
312 buf = malloc(ETH_BUF_SIZE);
313 if (buf == NULL) {
314 goto err;
315 }
316 g_array_append_val(pollfds, tap_pollfd);
317 if (exitfd >= 0) {
318 n_fds++;
319 g_array_append_val(pollfds, exit_pollfd);
320 pollfds_exitfd_idx = n_fds - 1;
321 }
322 if (api_socket != NULL) {
323 if ((apifd = api_bindlisten(api_socket)) < 0) {
324 goto err;
325 }
326 if ((apictx = api_ctx_alloc(cfg)) == NULL) {
327 fprintf(stderr, "api_ctx_alloc failed\n");
328 goto err;
329 }
330 api_pollfd.fd = apifd;
331 n_fds++;
332 g_array_append_val(pollfds, api_pollfd);
333 pollfds_apifd_idx = n_fds - 1;
334 }
335 signal(SIGPIPE, SIG_IGN);
336 if (cfg->enable_sandbox && create_sandbox() < 0) {
337 fprintf(stderr, "create_sandbox failed\n");
338 goto err;
339 }
340 if (cfg->enable_seccomp && enable_seccomp() < 0) {
341 fprintf(stderr, "enable_seccomp failed\n");
342 goto err;
343 }
344 if (readyfd >= 0) {
345 int rc = -1;
346 do
347 rc = write(readyfd, "1", 1);
348 while (rc < 0 && errno == EINTR);
349 close(readyfd);
350 }
351 while (1) {
352 int pollout;
353 GPollFD *pollfds_data;
354 uint32_t timeout = -1; /* msec */
355 g_array_set_size(pollfds, n_fds);
356 slirp_pollfds_fill(slirp, &timeout, libslirp_add_poll, pollfds);
357 update_ra_timeout(&timeout, &opaque);
358 pollfds_data = (GPollFD *)pollfds->data;
359 do {
360 pollout = g_poll(pollfds_data, pollfds->len, timeout);
361 } while (pollout < 0 && errno == EINTR);
362 if (pollout < 0) {
363 goto err;
364 }
365
366 if (pollfds_data[0].revents) {
367 ssize_t rc = read(tapfd, buf, ETH_BUF_SIZE);
368 if (rc < 0) {
369 perror("do_slirp: read");
370 goto after_slirp_input;
371 }
372 slirp_input(slirp, buf, (int)rc);
373 after_slirp_input:
374 pollout = -1;
375 }
376
377 /* The exitfd is closed. */
378 if (pollfds_exitfd_idx >= 0 &&
379 pollfds_data[pollfds_exitfd_idx].revents) {
380 fprintf(stderr, "exitfd event\n");
381 goto success;
382 }
383
384 if (pollfds_apifd_idx >= 0 && pollfds_data[pollfds_apifd_idx].revents) {
385 int rc;
386 fprintf(stderr, "apifd event\n");
387 if ((rc = api_handler(slirp, apifd, apictx)) < 0) {
388 fprintf(stderr, "api_handler: rc=%d\n", rc);
389 }
390 }
391
392 slirp_pollfds_poll(slirp, (pollout <= 0), libslirp_get_revents,
393 pollfds);
394 check_ra_timeout(&opaque);
395 }
396 success:
397 ret = 0;
398 err:
399 fprintf(stderr, "do_slirp is exiting\n");
400 if (buf != NULL) {
401 free(buf);
402 }
403 if (apictx != NULL) {
404 api_ctx_free(apictx);
405 unlink(api_socket);
406 }
407 g_array_free(pollfds, TRUE);
408 return ret;
409 }
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
01 #ifndef SLIRP4NETNS_H
12 # define SLIRP4NETNS_H
23 #include <arpa/inet.h>
1112 struct in_addr recommended_vguest; // 10.0.2.100 (slirp itself is unaware of vguest)
1213 bool enable_ipv6;
1314 bool disable_host_loopback;
15 bool enable_sandbox;
16 bool enable_seccomp;
1417 };
15 int do_slirp(int tapfd, int exitfd, const char *api_socket, struct slirp4netns_config *cfg);
18 int do_slirp(int tapfd, int readyfd, int exitfd, const char *api_socket, struct slirp4netns_config *cfg);
1619
1720 #endif
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 # it is a part of test-slirp4netns.sh
6 # must run in a new mount namespace
7
8 mount -t tmpfs tmpfs /run
9 mkdir /run/foo
10 mount -t tmpfs tmpfs /run/foo
11 mount --make-rshared /run
12
13 unshare -n sleep infinity &
14 child=$!
15
16 wait_for_network_namespace $child
17
18 ./slirp4netns --enable-sandbox --netns-type=path /proc/$child/ns/net tun11 &
19 slirp_pid=$!
20
21 function cleanup {
22 kill -9 $child $slirp_pid
23 }
24 trap cleanup EXIT
25
26 wait_for_network_device $child tun11
27
28 findmnt /run/foo
99
1010 tmpdir=$(mktemp -d /tmp/slirp4netns-bench.XXXXXXXXXX)
1111 apisocket=${tmpdir}/slirp4netns.sock
12 apisocketlongpath=${tmpdir}/slirp4netns-TOO-LONG-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.sock
13
14 if slirp4netns -c $child --api-socket $apisocketlongpath tun11; then
15 echo "expected failure with apisocket path too long" >&2
16 kill -9 $child
17 rm -rf $tmpdir
18 exit 1
19 fi
20
1221 slirp4netns -c $child --api-socket $apisocket tun11 &
1322 slirp_pid=$!
1423
22
33 . $(dirname $0)/common.sh
44
5
6 # Test --netns-type=pid
57 unshare -r -n sleep infinity &
68 child=$!
79
810 wait_for_network_namespace $child
911
10 slirp4netns $child tun11 &
12 slirp4netns --ready-fd=3 --enable-sandbox $child tun11 3>ready.file &
1113 slirp_pid=$!
1214
13 wait_for_network_device $child tun11
15 # Wait that the sandbox is created
16 wait_for_file_content 1 ready.file
17 rm ready.file
18
19 # Check there are no capabilities left in slirp4netns
20 getpcaps $slirp_pid 2>&1 | tail -n1 > slirp.caps
21 grep cap_net_bind_service slirp.caps
22 grep -v cap_sys_admin slirp.caps
23 rm slirp.caps
24 test -e /proc/$slirp_pid/root/etc
25 test -e /proc/$slirp_pid/root/run
26 test \! -e /proc/$slirp_pid/root/home
27 test \! -e /proc/$slirp_pid/root/root
28 test \! -e /proc/$slirp_pid/root/var
1429
1530 function cleanup {
1631 kill -9 $child $slirp_pid
1833 trap cleanup EXIT
1934
2035 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
36 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep -v inet
2137
38 kill -9 $child $slirp_pid
39
40 # Test --userns-path= --netns-type=path
41 unshare -r -n sleep infinity &
42 child=$!
43
44 wait_for_network_namespace $child
45
46 slirp4netns --userns-path=/proc/$child/ns/user --netns-type=path /proc/$child/ns/net tun11 &
47 slirp_pid=$!
48
49 wait_for_network_device $child tun11
50
51 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
2252 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep -v inet
53
54 kill -9 $child $slirp_pid
55
56 # Test --netns-type=path
57 unshare -r -n sleep infinity &
58 child=$!
59
60 wait_for_network_namespace $child
61
62 nsenter --preserve-credentials -U --target=$child slirp4netns --netns-type=path /proc/$child/ns/net tun11 &
63 slirp_pid=$!
64
65 wait_for_network_device $child tun11
66
67 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
68 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep -v inet
69
70 unshare -rm $(readlink -f $(dirname $0)/slirp4netns-no-unmount.sh)
00 # DO NOT EDIT MANUALLY
11
22 Vendored components:
3 * libslirp: https://gitlab.freedesktop.org/slirp/libslirp.git (`76462e2f16c6fce6856fb914cbef6207d0be4bc5`)
4 * parson: https://github.com/kgabis/parson.git (`c5bb9557fe98367aa8e041c65863909f12ee76b2`)
3 * parson: https://github.com/kgabis/parson.git (`70dc239f8f54c80bf58477b25435fd3dd3102804`)
54
65 Please do not edit the contents under this directory manually.
76
8 See also [`../vendor.md`](../vendor.md).
7 Use [`../vendor.sh`](../vendor.sh) to update the contents.
+0
-58
vendor/libslirp/.clang-format less more
0 # https://clang.llvm.org/docs/ClangFormat.html
1 # https://clang.llvm.org/docs/ClangFormatStyleOptions.html
2 ---
3 Language: Cpp
4 AlignAfterOpenBracket: Align
5 AlignConsecutiveAssignments: false # although we like it, it creates churn
6 AlignConsecutiveDeclarations: false
7 AlignEscapedNewlinesLeft: true
8 AlignOperands: true
9 AlignTrailingComments: false # churn
10 AllowAllParametersOfDeclarationOnNextLine: true
11 AllowShortBlocksOnASingleLine: false
12 AllowShortCaseLabelsOnASingleLine: false
13 AllowShortFunctionsOnASingleLine: None
14 AllowShortIfStatementsOnASingleLine: false
15 AllowShortLoopsOnASingleLine: false
16 AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
17 AlwaysBreakBeforeMultilineStrings: false
18 BinPackArguments: true
19 BinPackParameters: true
20 BraceWrapping:
21 AfterControlStatement: false
22 AfterEnum: false
23 AfterFunction: true
24 AfterStruct: false
25 AfterUnion: false
26 BeforeElse: false
27 IndentBraces: false
28 BreakBeforeBinaryOperators: None
29 BreakBeforeBraces: Custom
30 BreakBeforeTernaryOperators: false
31 BreakStringLiterals: true
32 ColumnLimit: 80
33 ContinuationIndentWidth: 4
34 Cpp11BracedListStyle: false
35 DerivePointerAlignment: false
36 DisableFormat: false
37 IndentCaseLabels: false
38 IndentWidth: 4
39 IndentWrappedFunctionNames: false
40 KeepEmptyLinesAtTheStartOfBlocks: false
41 MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
42 MacroBlockEnd: '.*_END$'
43 MaxEmptyLinesToKeep: 2
44 PointerAlignment: Right
45 ReflowComments: true
46 SortIncludes: false
47 SpaceAfterCStyleCast: false
48 SpaceBeforeAssignmentOperators: true
49 SpaceBeforeParens: ControlStatements
50 SpaceInEmptyParentheses: false
51 SpacesBeforeTrailingComments: 1
52 SpacesInContainerLiterals: true
53 SpacesInParentheses: false
54 SpacesInSquareBrackets: false
55 Standard: Auto
56 UseTab: Never
57 ...
+0
-62
vendor/libslirp/COPYRIGHT less more
0 Slirp was written by Danny Gasparovski.
1 Copyright (c), 1995,1996 All Rights Reserved.
2
3 Slirp is free software; "free" as in you don't have to pay for it, and you
4 are free to do whatever you want with it. I do not accept any donations,
5 monetary or otherwise, for Slirp. Instead, I would ask you to pass this
6 potential donation to your favorite charity. In fact, I encourage
7 *everyone* who finds Slirp useful to make a small donation to their
8 favorite charity (for example, GreenPeace). This is not a requirement, but
9 a suggestion from someone who highly values the service they provide.
10
11 The copyright terms and conditions:
12
13 ---BEGIN---
14
15 Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved.
16
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions
19 are met:
20 1. Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22 2. Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
25 3. Neither the name of the copyright holder nor the names of its
26 contributors may be used to endorse or promote products derived
27 from this software without specific prior written permission.
28
29 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
30 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
31 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
40 ---END---
41
42 This basically means you can do anything you want with the software, except
43 1) call it your own, and 2) claim warranty on it. There is no warranty for
44 this software. None. Nada. If you lose a million dollars while using
45 Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***.
46
47 If these conditions cannot be met due to legal restrictions (E.g. where it
48 is against the law to give out Software without warranty), you must cease
49 using the software and delete all copies you have.
50
51 Slirp uses code that is copyrighted by the following people/organizations:
52
53 Juha Pirkola.
54 Gregory M. Christy.
55 The Regents of the University of California.
56 Carnegie Mellon University.
57 The Australian National University.
58 RSA Data Security, Inc.
59
60 Please read the top of each source file for the details on the various
61 copyrights.
+0
-60
vendor/libslirp/README.md less more
0 # libslirp
1
2 libslirp is a user-mode networking library used by virtual machines,
3 containers or various tools.
4
5 ## Getting Started
6
7 ### Prerequisites
8
9 A C compiler, make/meson and glib2 development libraries.
10
11 (see also [.gitlab-ci.yml](.gitlab-ci.yml) DEPS variable for the list
12 of dependencies on Fedora)
13
14 ### Building
15
16 You may build and install the shared library with meson:
17
18 ``` sh
19 meson build
20 ninja -C build install
21 ```
22 And configure QEMU with --enable-slirp=system to link against it.
23
24 (QEMU may build with the submodule static library using --enable-slirp=git)
25
26 ### Testing
27
28 Unfortunately, there are no automated tests available.
29
30 You may run QEMU ``-net user`` linked with your development version.
31
32 ## Contributing
33
34 Feel free to open issues on the [project
35 issues](https://gitlab.freedesktop.org/slirp/libslirp/issues) page.
36
37 You may clone the [gitlab
38 project](https://gitlab.freedesktop.org/slirp/libslirp) and create a
39 merge request.
40
41 Contributing with gitlab allows gitlab workflow, tracking issues,
42 running CI etc.
43
44 Alternatively, you may send patches to slirp@lists.freedesktop.org
45 mailing list.
46
47 ## Versioning
48
49 We intend to use [libtool's
50 versioning](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
51 for the shared libraries and use [SemVer](http://semver.org/) for
52 project versions.
53
54 For the versions available, see the [tags on this
55 repository](https://gitlab.freedesktop.org/slirp/libslirp/releases).
56
57 ## License
58
59 See the [COPYRIGHT](COPYRIGHT) file for details.
+0
-91
vendor/libslirp/src/arp_table.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * ARP table
3 *
4 * Copyright (c) 2011 AdaCore
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "slirp.h"
26
27 #include <string.h>
28
29 void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
30 {
31 const uint32_t broadcast_addr =
32 ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
33 ArpTable *arptbl = &slirp->arp_table;
34 int i;
35
36 DEBUG_CALL("arp_table_add");
37 DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
38 DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1],
39 ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
40
41 if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
42 /* Do not register broadcast addresses */
43 return;
44 }
45
46 /* Search for an entry */
47 for (i = 0; i < ARP_TABLE_SIZE; i++) {
48 if (arptbl->table[i].ar_sip == ip_addr) {
49 /* Update the entry */
50 memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
51 return;
52 }
53 }
54
55 /* No entry found, create a new one */
56 arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
57 memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
58 arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
59 }
60
61 bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
62 uint8_t out_ethaddr[ETH_ALEN])
63 {
64 const uint32_t broadcast_addr =
65 ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
66 ArpTable *arptbl = &slirp->arp_table;
67 int i;
68
69 DEBUG_CALL("arp_table_search");
70 DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
71
72 /* If broadcast address */
73 if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
74 /* return Ethernet broadcast address */
75 memset(out_ethaddr, 0xff, ETH_ALEN);
76 return 1;
77 }
78
79 for (i = 0; i < ARP_TABLE_SIZE; i++) {
80 if (arptbl->table[i].ar_sip == ip_addr) {
81 memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
82 DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
83 out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
84 out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
85 return 1;
86 }
87 }
88
89 return 0;
90 }
+0
-368
vendor/libslirp/src/bootp.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * QEMU BOOTP/DHCP server
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "slirp.h"
25
26 #if defined(_WIN32)
27 /* Windows ntohl() returns an u_long value.
28 * Add a type cast to match the format strings. */
29 #define ntohl(n) ((uint32_t)ntohl(n))
30 #endif
31
32 /* XXX: only DHCP is supported */
33
34 #define LEASE_TIME (24 * 3600)
35
36 static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
37
38 #define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__)
39
40 static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
41 const uint8_t *macaddr)
42 {
43 BOOTPClient *bc;
44 int i;
45
46 for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
47 bc = &slirp->bootp_clients[i];
48 if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
49 goto found;
50 }
51 return NULL;
52 found:
53 bc = &slirp->bootp_clients[i];
54 bc->allocated = 1;
55 paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
56 return bc;
57 }
58
59 static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
60 const uint8_t *macaddr)
61 {
62 uint32_t req_addr = ntohl(paddr->s_addr);
63 uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
64 BOOTPClient *bc;
65
66 if (req_addr >= dhcp_addr && req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
67 bc = &slirp->bootp_clients[req_addr - dhcp_addr];
68 if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
69 bc->allocated = 1;
70 return bc;
71 }
72 }
73 return NULL;
74 }
75
76 static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
77 const uint8_t *macaddr)
78 {
79 BOOTPClient *bc;
80 int i;
81
82 for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
83 if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
84 goto found;
85 }
86 return NULL;
87 found:
88 bc = &slirp->bootp_clients[i];
89 bc->allocated = 1;
90 paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
91 return bc;
92 }
93
94 static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
95 struct in_addr *preq_addr)
96 {
97 const uint8_t *p, *p_end;
98 int len, tag;
99
100 *pmsg_type = 0;
101 preq_addr->s_addr = htonl(0L);
102
103 p = bp->bp_vend;
104 p_end = p + DHCP_OPT_LEN;
105 if (memcmp(p, rfc1533_cookie, 4) != 0)
106 return;
107 p += 4;
108 while (p < p_end) {
109 tag = p[0];
110 if (tag == RFC1533_PAD) {
111 p++;
112 } else if (tag == RFC1533_END) {
113 break;
114 } else {
115 p++;
116 if (p >= p_end)
117 break;
118 len = *p++;
119 if (p + len > p_end) {
120 break;
121 }
122 DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
123
124 switch (tag) {
125 case RFC2132_MSG_TYPE:
126 if (len >= 1)
127 *pmsg_type = p[0];
128 break;
129 case RFC2132_REQ_ADDR:
130 if (len >= 4) {
131 memcpy(&(preq_addr->s_addr), p, 4);
132 }
133 break;
134 default:
135 break;
136 }
137 p += len;
138 }
139 }
140 if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
141 bp->bp_ciaddr.s_addr) {
142 memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
143 }
144 }
145
146 static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
147 {
148 BOOTPClient *bc = NULL;
149 struct mbuf *m;
150 struct bootp_t *rbp;
151 struct sockaddr_in saddr, daddr;
152 struct in_addr preq_addr;
153 int dhcp_msg_type, val;
154 uint8_t *q;
155 uint8_t *end;
156 uint8_t client_ethaddr[ETH_ALEN];
157
158 /* extract exact DHCP msg type */
159 dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
160 DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
161 if (preq_addr.s_addr != htonl(0L))
162 DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
163 else {
164 DPRINTF("\n");
165 }
166
167 if (dhcp_msg_type == 0)
168 dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
169
170 if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST)
171 return;
172
173 /* Get client's hardware address from bootp request */
174 memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
175
176 m = m_get(slirp);
177 if (!m) {
178 return;
179 }
180 m->m_data += IF_MAXLINKHDR;
181 rbp = (struct bootp_t *)m->m_data;
182 m->m_data += sizeof(struct udpiphdr);
183 memset(rbp, 0, sizeof(struct bootp_t));
184
185 if (dhcp_msg_type == DHCPDISCOVER) {
186 if (preq_addr.s_addr != htonl(0L)) {
187 bc = request_addr(slirp, &preq_addr, client_ethaddr);
188 if (bc) {
189 daddr.sin_addr = preq_addr;
190 }
191 }
192 if (!bc) {
193 new_addr:
194 bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
195 if (!bc) {
196 DPRINTF("no address left\n");
197 return;
198 }
199 }
200 memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
201 } else if (preq_addr.s_addr != htonl(0L)) {
202 bc = request_addr(slirp, &preq_addr, client_ethaddr);
203 if (bc) {
204 daddr.sin_addr = preq_addr;
205 memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
206 } else {
207 /* DHCPNAKs should be sent to broadcast */
208 daddr.sin_addr.s_addr = 0xffffffff;
209 }
210 } else {
211 bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
212 if (!bc) {
213 /* if never assigned, behaves as if it was already
214 assigned (windows fix because it remembers its address) */
215 goto new_addr;
216 }
217 }
218
219 /* Update ARP table for this IP address */
220 arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
221
222 saddr.sin_addr = slirp->vhost_addr;
223 saddr.sin_port = htons(BOOTP_SERVER);
224
225 daddr.sin_port = htons(BOOTP_CLIENT);
226
227 rbp->bp_op = BOOTP_REPLY;
228 rbp->bp_xid = bp->bp_xid;
229 rbp->bp_htype = 1;
230 rbp->bp_hlen = 6;
231 memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
232
233 rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
234 rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
235
236 q = rbp->bp_vend;
237 end = (uint8_t *)&rbp[1];
238 memcpy(q, rfc1533_cookie, 4);
239 q += 4;
240
241 if (bc) {
242 DPRINTF("%s addr=%08" PRIx32 "\n",
243 (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
244 ntohl(daddr.sin_addr.s_addr));
245
246 if (dhcp_msg_type == DHCPDISCOVER) {
247 *q++ = RFC2132_MSG_TYPE;
248 *q++ = 1;
249 *q++ = DHCPOFFER;
250 } else /* DHCPREQUEST */ {
251 *q++ = RFC2132_MSG_TYPE;
252 *q++ = 1;
253 *q++ = DHCPACK;
254 }
255
256 if (slirp->bootp_filename)
257 snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
258 slirp->bootp_filename);
259
260 *q++ = RFC2132_SRV_ID;
261 *q++ = 4;
262 memcpy(q, &saddr.sin_addr, 4);
263 q += 4;
264
265 *q++ = RFC1533_NETMASK;
266 *q++ = 4;
267 memcpy(q, &slirp->vnetwork_mask, 4);
268 q += 4;
269
270 if (!slirp->restricted) {
271 *q++ = RFC1533_GATEWAY;
272 *q++ = 4;
273 memcpy(q, &saddr.sin_addr, 4);
274 q += 4;
275
276 *q++ = RFC1533_DNS;
277 *q++ = 4;
278 memcpy(q, &slirp->vnameserver_addr, 4);
279 q += 4;
280 }
281
282 *q++ = RFC2132_LEASE_TIME;
283 *q++ = 4;
284 val = htonl(LEASE_TIME);
285 memcpy(q, &val, 4);
286 q += 4;
287
288 if (*slirp->client_hostname) {
289 val = strlen(slirp->client_hostname);
290 if (q + val + 2 >= end) {
291 g_warning("DHCP packet size exceeded, "
292 "omitting host name option.");
293 } else {
294 *q++ = RFC1533_HOSTNAME;
295 *q++ = val;
296 memcpy(q, slirp->client_hostname, val);
297 q += val;
298 }
299 }
300
301 if (slirp->vdomainname) {
302 val = strlen(slirp->vdomainname);
303 if (q + val + 2 >= end) {
304 g_warning("DHCP packet size exceeded, "
305 "omitting domain name option.");
306 } else {
307 *q++ = RFC1533_DOMAINNAME;
308 *q++ = val;
309 memcpy(q, slirp->vdomainname, val);
310 q += val;
311 }
312 }
313
314 if (slirp->tftp_server_name) {
315 val = strlen(slirp->tftp_server_name);
316 if (q + val + 2 >= end) {
317 g_warning("DHCP packet size exceeded, "
318 "omitting tftp-server-name option.");
319 } else {
320 *q++ = RFC2132_TFTP_SERVER_NAME;
321 *q++ = val;
322 memcpy(q, slirp->tftp_server_name, val);
323 q += val;
324 }
325 }
326
327 if (slirp->vdnssearch) {
328 val = slirp->vdnssearch_len;
329 if (q + val >= end) {
330 g_warning("DHCP packet size exceeded, "
331 "omitting domain-search option.");
332 } else {
333 memcpy(q, slirp->vdnssearch, val);
334 q += val;
335 }
336 }
337 } else {
338 static const char nak_msg[] = "requested address not available";
339
340 DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
341
342 *q++ = RFC2132_MSG_TYPE;
343 *q++ = 1;
344 *q++ = DHCPNAK;
345
346 *q++ = RFC2132_MESSAGE;
347 *q++ = sizeof(nak_msg) - 1;
348 memcpy(q, nak_msg, sizeof(nak_msg) - 1);
349 q += sizeof(nak_msg) - 1;
350 }
351 assert(q < end);
352 *q = RFC1533_END;
353
354 daddr.sin_addr.s_addr = 0xffffffffu;
355
356 m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr);
357 udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
358 }
359
360 void bootp_input(struct mbuf *m)
361 {
362 struct bootp_t *bp = mtod(m, struct bootp_t *);
363
364 if (bp->bp_op == BOOTP_REQUEST) {
365 bootp_reply(m->slirp, bp);
366 }
367 }
+0
-129
vendor/libslirp/src/bootp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /* bootp/dhcp defines */
2
3 #ifndef SLIRP_BOOTP_H
4 #define SLIRP_BOOTP_H
5
6 #define BOOTP_SERVER 67
7 #define BOOTP_CLIENT 68
8
9 #define BOOTP_REQUEST 1
10 #define BOOTP_REPLY 2
11
12 #define RFC1533_COOKIE 99, 130, 83, 99
13 #define RFC1533_PAD 0
14 #define RFC1533_NETMASK 1
15 #define RFC1533_TIMEOFFSET 2
16 #define RFC1533_GATEWAY 3
17 #define RFC1533_TIMESERVER 4
18 #define RFC1533_IEN116NS 5
19 #define RFC1533_DNS 6
20 #define RFC1533_LOGSERVER 7
21 #define RFC1533_COOKIESERVER 8
22 #define RFC1533_LPRSERVER 9
23 #define RFC1533_IMPRESSSERVER 10
24 #define RFC1533_RESOURCESERVER 11
25 #define RFC1533_HOSTNAME 12
26 #define RFC1533_BOOTFILESIZE 13
27 #define RFC1533_MERITDUMPFILE 14
28 #define RFC1533_DOMAINNAME 15
29 #define RFC1533_SWAPSERVER 16
30 #define RFC1533_ROOTPATH 17
31 #define RFC1533_EXTENSIONPATH 18
32 #define RFC1533_IPFORWARDING 19
33 #define RFC1533_IPSOURCEROUTING 20
34 #define RFC1533_IPPOLICYFILTER 21
35 #define RFC1533_IPMAXREASSEMBLY 22
36 #define RFC1533_IPTTL 23
37 #define RFC1533_IPMTU 24
38 #define RFC1533_IPMTUPLATEAU 25
39 #define RFC1533_INTMTU 26
40 #define RFC1533_INTLOCALSUBNETS 27
41 #define RFC1533_INTBROADCAST 28
42 #define RFC1533_INTICMPDISCOVER 29
43 #define RFC1533_INTICMPRESPOND 30
44 #define RFC1533_INTROUTEDISCOVER 31
45 #define RFC1533_INTROUTESOLICIT 32
46 #define RFC1533_INTSTATICROUTES 33
47 #define RFC1533_LLTRAILERENCAP 34
48 #define RFC1533_LLARPCACHETMO 35
49 #define RFC1533_LLETHERNETENCAP 36
50 #define RFC1533_TCPTTL 37
51 #define RFC1533_TCPKEEPALIVETMO 38
52 #define RFC1533_TCPKEEPALIVEGB 39
53 #define RFC1533_NISDOMAIN 40
54 #define RFC1533_NISSERVER 41
55 #define RFC1533_NTPSERVER 42
56 #define RFC1533_VENDOR 43
57 #define RFC1533_NBNS 44
58 #define RFC1533_NBDD 45
59 #define RFC1533_NBNT 46
60 #define RFC1533_NBSCOPE 47
61 #define RFC1533_XFS 48
62 #define RFC1533_XDM 49
63
64 #define RFC2132_REQ_ADDR 50
65 #define RFC2132_LEASE_TIME 51
66 #define RFC2132_MSG_TYPE 53
67 #define RFC2132_SRV_ID 54
68 #define RFC2132_PARAM_LIST 55
69 #define RFC2132_MESSAGE 56
70 #define RFC2132_MAX_SIZE 57
71 #define RFC2132_RENEWAL_TIME 58
72 #define RFC2132_REBIND_TIME 59
73 #define RFC2132_TFTP_SERVER_NAME 66
74
75 #define DHCPDISCOVER 1
76 #define DHCPOFFER 2
77 #define DHCPREQUEST 3
78 #define DHCPACK 5
79 #define DHCPNAK 6
80
81 #define RFC1533_VENDOR_MAJOR 0
82 #define RFC1533_VENDOR_MINOR 0
83
84 #define RFC1533_VENDOR_MAGIC 128
85 #define RFC1533_VENDOR_ADDPARM 129
86 #define RFC1533_VENDOR_ETHDEV 130
87 #define RFC1533_VENDOR_HOWTO 132
88 #define RFC1533_VENDOR_MNUOPTS 160
89 #define RFC1533_VENDOR_SELECTION 176
90 #define RFC1533_VENDOR_MOTD 184
91 #define RFC1533_VENDOR_NUMOFMOTD 8
92 #define RFC1533_VENDOR_IMG 192
93 #define RFC1533_VENDOR_NUMOFIMG 16
94
95 #define RFC1533_END 255
96 #define BOOTP_VENDOR_LEN 64
97 #define DHCP_OPT_LEN 312
98
99 struct bootp_t {
100 struct ip ip;
101 struct udphdr udp;
102 uint8_t bp_op;
103 uint8_t bp_htype;
104 uint8_t bp_hlen;
105 uint8_t bp_hops;
106 uint32_t bp_xid;
107 uint16_t bp_secs;
108 uint16_t unused;
109 struct in_addr bp_ciaddr;
110 struct in_addr bp_yiaddr;
111 struct in_addr bp_siaddr;
112 struct in_addr bp_giaddr;
113 uint8_t bp_hwaddr[16];
114 uint8_t bp_sname[64];
115 uint8_t bp_file[128];
116 uint8_t bp_vend[DHCP_OPT_LEN];
117 };
118
119 typedef struct {
120 uint16_t allocated;
121 uint8_t macaddr[6];
122 } BOOTPClient;
123
124 #define NB_BOOTP_CLIENTS 16
125
126 void bootp_input(struct mbuf *m);
127
128 #endif
+0
-179
vendor/libslirp/src/cksum.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1988, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
30 * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
31 */
32
33 #include "slirp.h"
34
35 /*
36 * Checksum routine for Internet Protocol family headers (Portable Version).
37 *
38 * This routine is very heavily used in the network
39 * code and should be modified for each CPU to be as fast as possible.
40 *
41 * XXX Since we will never span more than 1 mbuf, we can optimise this
42 */
43
44 #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
45 #define REDUCE \
46 { \
47 l_util.l = sum; \
48 sum = l_util.s[0] + l_util.s[1]; \
49 (void)ADDCARRY(sum); \
50 }
51
52 int cksum(struct mbuf *m, int len)
53 {
54 register uint16_t *w;
55 register int sum = 0;
56 register int mlen = 0;
57 int byte_swapped = 0;
58
59 union {
60 uint8_t c[2];
61 uint16_t s;
62 } s_util;
63 union {
64 uint16_t s[2];
65 uint32_t l;
66 } l_util;
67
68 if (m->m_len == 0)
69 goto cont;
70 w = mtod(m, uint16_t *);
71
72 mlen = m->m_len;
73
74 if (len < mlen)
75 mlen = len;
76 len -= mlen;
77 /*
78 * Force to even boundary.
79 */
80 if ((1 & (uintptr_t)w) && (mlen > 0)) {
81 REDUCE;
82 sum <<= 8;
83 s_util.c[0] = *(uint8_t *)w;
84 w = (uint16_t *)((int8_t *)w + 1);
85 mlen--;
86 byte_swapped = 1;
87 }
88 /*
89 * Unroll the loop to make overhead from
90 * branches &c small.
91 */
92 while ((mlen -= 32) >= 0) {
93 sum += w[0];
94 sum += w[1];
95 sum += w[2];
96 sum += w[3];
97 sum += w[4];
98 sum += w[5];
99 sum += w[6];
100 sum += w[7];
101 sum += w[8];
102 sum += w[9];
103 sum += w[10];
104 sum += w[11];
105 sum += w[12];
106 sum += w[13];
107 sum += w[14];
108 sum += w[15];
109 w += 16;
110 }
111 mlen += 32;
112 while ((mlen -= 8) >= 0) {
113 sum += w[0];
114 sum += w[1];
115 sum += w[2];
116 sum += w[3];
117 w += 4;
118 }
119 mlen += 8;
120 if (mlen == 0 && byte_swapped == 0)
121 goto cont;
122 REDUCE;
123 while ((mlen -= 2) >= 0) {
124 sum += *w++;
125 }
126
127 if (byte_swapped) {
128 REDUCE;
129 sum <<= 8;
130 if (mlen == -1) {
131 s_util.c[1] = *(uint8_t *)w;
132 sum += s_util.s;
133 mlen = 0;
134 } else
135
136 mlen = -1;
137 } else if (mlen == -1)
138 s_util.c[0] = *(uint8_t *)w;
139
140 cont:
141 if (len) {
142 DEBUG_ERROR("cksum: out of data");
143 DEBUG_ERROR(" len = %d", len);
144 }
145 if (mlen == -1) {
146 /* The last mbuf has odd # of bytes. Follow the
147 standard (the odd byte may be shifted left by 8 bits
148 or not as determined by endian-ness of the machine) */
149 s_util.c[1] = 0;
150 sum += s_util.s;
151 }
152 REDUCE;
153 return (~sum & 0xffff);
154 }
155
156 int ip6_cksum(struct mbuf *m)
157 {
158 /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
159 * separately from the mbuf */
160 struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
161 struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
162 int sum;
163
164 save_ip = *ip;
165
166 ih->ih_src = save_ip.ip_src;
167 ih->ih_dst = save_ip.ip_dst;
168 ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
169 ih->ih_zero_hi = 0;
170 ih->ih_zero_lo = 0;
171 ih->ih_nh = save_ip.ip_nh;
172
173 sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl));
174
175 *ip = save_ip;
176
177 return sum;
178 }
+0
-51
vendor/libslirp/src/debug.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #ifndef DEBUG_H_
6 #define DEBUG_H_
7
8 #define DBG_CALL (1 << 0)
9 #define DBG_MISC (1 << 1)
10 #define DBG_ERROR (1 << 2)
11 #define DBG_TFTP (1 << 3)
12
13 extern int slirp_debug;
14
15 #define DEBUG_CALL(fmt, ...) \
16 do { \
17 if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
18 g_debug(fmt "...", ##__VA_ARGS__); \
19 } \
20 } while (0)
21
22 #define DEBUG_ARG(fmt, ...) \
23 do { \
24 if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
25 g_debug(" " fmt, ##__VA_ARGS__); \
26 } \
27 } while (0)
28
29 #define DEBUG_MISC(fmt, ...) \
30 do { \
31 if (G_UNLIKELY(slirp_debug & DBG_MISC)) { \
32 g_debug(fmt, ##__VA_ARGS__); \
33 } \
34 } while (0)
35
36 #define DEBUG_ERROR(fmt, ...) \
37 do { \
38 if (G_UNLIKELY(slirp_debug & DBG_ERROR)) { \
39 g_debug(fmt, ##__VA_ARGS__); \
40 } \
41 } while (0)
42
43 #define DEBUG_TFTP(fmt, ...) \
44 do { \
45 if (G_UNLIKELY(slirp_debug & DBG_TFTP)) { \
46 g_debug(fmt, ##__VA_ARGS__); \
47 } \
48 } while (0)
49
50 #endif /* DEBUG_H_ */
+0
-225
vendor/libslirp/src/dhcpv6.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * SLIRP stateless DHCPv6
3 *
4 * We only support stateless DHCPv6, e.g. for network booting.
5 * See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
6 *
7 * Copyright 2016 Thomas Huth, Red Hat Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
21 *
22 * 3. Neither the name of the copyright holder nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37 * OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include "slirp.h"
41 #include "dhcpv6.h"
42
43 /* DHCPv6 message types */
44 #define MSGTYPE_REPLY 7
45 #define MSGTYPE_INFO_REQUEST 11
46
47 /* DHCPv6 option types */
48 #define OPTION_CLIENTID 1
49 #define OPTION_IAADDR 5
50 #define OPTION_ORO 6
51 #define OPTION_DNS_SERVERS 23
52 #define OPTION_BOOTFILE_URL 59
53
54 struct requested_infos {
55 uint8_t *client_id;
56 int client_id_len;
57 bool want_dns;
58 bool want_boot_url;
59 };
60
61 /**
62 * Analyze the info request message sent by the client to see what data it
63 * provided and what it wants to have. The information is gathered in the
64 * "requested_infos" struct. Note that client_id (if provided) points into
65 * the odata region, thus the caller must keep odata valid as long as it
66 * needs to access the requested_infos struct.
67 */
68 static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
69 struct requested_infos *ri)
70 {
71 int i, req_opt;
72
73 while (olen > 4) {
74 /* Parse one option */
75 int option = odata[0] << 8 | odata[1];
76 int len = odata[2] << 8 | odata[3];
77
78 if (len + 4 > olen) {
79 slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",
80 slirp->opaque);
81 return -E2BIG;
82 }
83
84 switch (option) {
85 case OPTION_IAADDR:
86 /* According to RFC3315, we must discard requests with IA option */
87 return -EINVAL;
88 case OPTION_CLIENTID:
89 if (len > 256) {
90 /* Avoid very long IDs which could cause problems later */
91 return -E2BIG;
92 }
93 ri->client_id = odata + 4;
94 ri->client_id_len = len;
95 break;
96 case OPTION_ORO: /* Option request option */
97 if (len & 1) {
98 return -EINVAL;
99 }
100 /* Check which options the client wants to have */
101 for (i = 0; i < len; i += 2) {
102 req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
103 switch (req_opt) {
104 case OPTION_DNS_SERVERS:
105 ri->want_dns = true;
106 break;
107 case OPTION_BOOTFILE_URL:
108 ri->want_boot_url = true;
109 break;
110 default:
111 DEBUG_MISC("dhcpv6: Unsupported option request %d",
112 req_opt);
113 }
114 }
115 break;
116 default:
117 DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,
118 len);
119 }
120
121 odata += len + 4;
122 olen -= len + 4;
123 }
124
125 return 0;
126 }
127
128
129 /**
130 * Handle information request messages
131 */
132 static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
133 uint32_t xid, uint8_t *odata, int olen)
134 {
135 struct requested_infos ri = { NULL };
136 struct sockaddr_in6 sa6, da6;
137 struct mbuf *m;
138 uint8_t *resp;
139
140 if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
141 return;
142 }
143
144 m = m_get(slirp);
145 if (!m) {
146 return;
147 }
148 memset(m->m_data, 0, m->m_size);
149 m->m_data += IF_MAXLINKHDR;
150 resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
151
152 /* Fill in response */
153 *resp++ = MSGTYPE_REPLY;
154 *resp++ = (uint8_t)(xid >> 16);
155 *resp++ = (uint8_t)(xid >> 8);
156 *resp++ = (uint8_t)xid;
157
158 if (ri.client_id) {
159 *resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */
160 *resp++ = OPTION_CLIENTID; /* option-code low byte */
161 *resp++ = ri.client_id_len >> 8; /* option-len high byte */
162 *resp++ = ri.client_id_len; /* option-len low byte */
163 memcpy(resp, ri.client_id, ri.client_id_len);
164 resp += ri.client_id_len;
165 }
166 if (ri.want_dns) {
167 *resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */
168 *resp++ = OPTION_DNS_SERVERS; /* option-code low byte */
169 *resp++ = 0; /* option-len high byte */
170 *resp++ = 16; /* option-len low byte */
171 memcpy(resp, &slirp->vnameserver_addr6, 16);
172 resp += 16;
173 }
174 if (ri.want_boot_url) {
175 uint8_t *sa = slirp->vhost_addr6.s6_addr;
176 int slen, smaxlen;
177
178 *resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
179 *resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
180 smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);
181 slen = snprintf((char *)resp + 2, smaxlen,
182 "tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
183 "%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
184 sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
185 sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
186 sa[15], slirp->bootp_filename);
187 slen = MIN(slen, smaxlen);
188 *resp++ = slen >> 8; /* option-len high byte */
189 *resp++ = slen; /* option-len low byte */
190 resp += slen;
191 }
192
193 sa6.sin6_addr = slirp->vhost_addr6;
194 sa6.sin6_port = DHCPV6_SERVER_PORT;
195 da6.sin6_addr = srcsas->sin6_addr;
196 da6.sin6_port = srcsas->sin6_port;
197 m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
198 m->m_len = resp - (uint8_t *)m->m_data;
199 udp6_output(NULL, m, &sa6, &da6);
200 }
201
202 /**
203 * Handle DHCPv6 messages sent by the client
204 */
205 void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
206 {
207 uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
208 int data_len = m->m_len - sizeof(struct udphdr);
209 uint32_t xid;
210
211 if (data_len < 4) {
212 return;
213 }
214
215 xid = ntohl(*(uint32_t *)data) & 0xffffff;
216
217 switch (data[0]) {
218 case MSGTYPE_INFO_REQUEST:
219 dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
220 break;
221 default:
222 DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
223 }
224 }
+0
-68
vendor/libslirp/src/dhcpv6.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Definitions and prototypes for SLIRP stateless DHCPv6
3 *
4 * Copyright 2016 Thomas Huth, Red Hat Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * 3. Neither the name of the copyright holder nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36 #ifndef SLIRP_DHCPV6_H
37 #define SLIRP_DHCPV6_H
38
39 #define DHCPV6_SERVER_PORT 547
40
41 #define ALLDHCP_MULTICAST \
42 { \
43 .s6_addr = { \
44 0xff, \
45 0x02, \
46 0x00, \
47 0x00, \
48 0x00, \
49 0x00, \
50 0x00, \
51 0x00, \
52 0x00, \
53 0x00, \
54 0x00, \
55 0x00, \
56 0x00, \
57 0x01, \
58 0x00, \
59 0x02 \
60 } \
61 }
62
63 #define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
64
65 void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
66
67 #endif
+0
-311
vendor/libslirp/src/dnssearch.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * Domain search option for DHCP (RFC 3397)
3 *
4 * Copyright (c) 2012 Klaus Stengel
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "slirp.h"
26
27 static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119;
28 static const uint8_t MAX_OPT_LEN = 255;
29 static const uint8_t OPT_HEADER_LEN = 2;
30 static const uint8_t REFERENCE_LEN = 2;
31
32 struct compact_domain;
33
34 typedef struct compact_domain {
35 struct compact_domain *self;
36 struct compact_domain *refdom;
37 uint8_t *labels;
38 size_t len;
39 size_t common_octets;
40 } CompactDomain;
41
42 static size_t domain_suffix_diffoff(const CompactDomain *a,
43 const CompactDomain *b)
44 {
45 size_t la = a->len, lb = b->len;
46 uint8_t *da = a->labels + la, *db = b->labels + lb;
47 size_t i, lm = (la < lb) ? la : lb;
48
49 for (i = 0; i < lm; i++) {
50 da--;
51 db--;
52 if (*da != *db) {
53 break;
54 }
55 }
56 return i;
57 }
58
59 static int domain_suffix_ord(const void *cva, const void *cvb)
60 {
61 const CompactDomain *a = cva, *b = cvb;
62 size_t la = a->len, lb = b->len;
63 size_t doff = domain_suffix_diffoff(a, b);
64 uint8_t ca = a->labels[la - doff];
65 uint8_t cb = b->labels[lb - doff];
66
67 if (ca < cb) {
68 return -1;
69 }
70 if (ca > cb) {
71 return 1;
72 }
73 if (la < lb) {
74 return -1;
75 }
76 if (la > lb) {
77 return 1;
78 }
79 return 0;
80 }
81
82 static size_t domain_common_label(CompactDomain *a, CompactDomain *b)
83 {
84 size_t res, doff = domain_suffix_diffoff(a, b);
85 uint8_t *first_eq_pos = a->labels + (a->len - doff);
86 uint8_t *label = a->labels;
87
88 while (*label && label < first_eq_pos) {
89 label += *label + 1;
90 }
91 res = a->len - (label - a->labels);
92 /* only report if it can help to reduce the packet size */
93 return (res > REFERENCE_LEN) ? res : 0;
94 }
95
96 static void domain_fixup_order(CompactDomain *cd, size_t n)
97 {
98 size_t i;
99
100 for (i = 0; i < n; i++) {
101 CompactDomain *cur = cd + i, *next = cd[i].self;
102
103 while (!cur->common_octets) {
104 CompactDomain *tmp = next->self; /* backup target value */
105
106 next->self = cur;
107 cur->common_octets++;
108
109 cur = next;
110 next = tmp;
111 }
112 }
113 }
114
115 static void domain_mklabels(CompactDomain *cd, const char *input)
116 {
117 uint8_t *len_marker = cd->labels;
118 uint8_t *output = len_marker; /* pre-incremented */
119 const char *in = input;
120 char cur_chr;
121 size_t len = 0;
122
123 if (cd->len == 0) {
124 goto fail;
125 }
126 cd->len++;
127
128 do {
129 cur_chr = *in++;
130 if (cur_chr == '.' || cur_chr == '\0') {
131 len = output - len_marker;
132 if ((len == 0 && cur_chr == '.') || len >= 64) {
133 goto fail;
134 }
135 *len_marker = len;
136
137 output++;
138 len_marker = output;
139 } else {
140 output++;
141 *output = cur_chr;
142 }
143 } while (cur_chr != '\0');
144
145 /* ensure proper zero-termination */
146 if (len != 0) {
147 *len_marker = 0;
148 cd->len++;
149 }
150 return;
151
152 fail:
153 g_warning("failed to parse domain name '%s'\n", input);
154 cd->len = 0;
155 }
156
157 static void domain_mkxrefs(CompactDomain *doms, CompactDomain *last,
158 size_t depth)
159 {
160 CompactDomain *i = doms, *target = doms;
161
162 do {
163 if (i->labels < target->labels) {
164 target = i;
165 }
166 } while (i++ != last);
167
168 for (i = doms; i != last; i++) {
169 CompactDomain *group_last;
170 size_t next_depth;
171
172 if (i->common_octets == depth) {
173 continue;
174 }
175
176 next_depth = -1;
177 for (group_last = i; group_last != last; group_last++) {
178 size_t co = group_last->common_octets;
179 if (co <= depth) {
180 break;
181 }
182 if (co < next_depth) {
183 next_depth = co;
184 }
185 }
186 domain_mkxrefs(i, group_last, next_depth);
187
188 i = group_last;
189 if (i == last) {
190 break;
191 }
192 }
193
194 if (depth == 0) {
195 return;
196 }
197
198 i = doms;
199 do {
200 if (i != target && i->refdom == NULL) {
201 i->refdom = target;
202 i->common_octets = depth;
203 }
204 } while (i++ != last);
205 }
206
207 static size_t domain_compactify(CompactDomain *domains, size_t n)
208 {
209 uint8_t *start = domains->self->labels, *outptr = start;
210 size_t i;
211
212 for (i = 0; i < n; i++) {
213 CompactDomain *cd = domains[i].self;
214 CompactDomain *rd = cd->refdom;
215
216 if (rd != NULL) {
217 size_t moff = (rd->labels - start) + (rd->len - cd->common_octets);
218 if (moff < 0x3FFFu) {
219 cd->len -= cd->common_octets - 2;
220 cd->labels[cd->len - 1] = moff & 0xFFu;
221 cd->labels[cd->len - 2] = 0xC0u | (moff >> 8);
222 }
223 }
224
225 if (cd->labels != outptr) {
226 memmove(outptr, cd->labels, cd->len);
227 cd->labels = outptr;
228 }
229 outptr += cd->len;
230 }
231 return outptr - start;
232 }
233
234 int translate_dnssearch(Slirp *s, const char **names)
235 {
236 size_t blocks, bsrc_start, bsrc_end, bdst_start;
237 size_t i, num_domains, memreq = 0;
238 uint8_t *result = NULL, *outptr;
239 CompactDomain *domains = NULL;
240 const char **nameptr = names;
241
242 while (*nameptr != NULL) {
243 nameptr++;
244 }
245
246 num_domains = nameptr - names;
247 if (num_domains == 0) {
248 return -2;
249 }
250
251 domains = g_malloc(num_domains * sizeof(*domains));
252
253 for (i = 0; i < num_domains; i++) {
254 size_t nlen = strlen(names[i]);
255 memreq += nlen + 2; /* 1 zero octet + 1 label length octet */
256 domains[i].self = domains + i;
257 domains[i].len = nlen;
258 domains[i].common_octets = 0;
259 domains[i].refdom = NULL;
260 }
261
262 /* reserve extra 2 header bytes for each 255 bytes of output */
263 memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN;
264 result = g_malloc(memreq * sizeof(*result));
265
266 outptr = result;
267 for (i = 0; i < num_domains; i++) {
268 domains[i].labels = outptr;
269 domain_mklabels(domains + i, names[i]);
270 outptr += domains[i].len;
271 }
272
273 if (outptr == result) {
274 g_free(domains);
275 g_free(result);
276 return -1;
277 }
278
279 qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord);
280 domain_fixup_order(domains, num_domains);
281
282 for (i = 1; i < num_domains; i++) {
283 size_t cl = domain_common_label(domains + i - 1, domains + i);
284 domains[i - 1].common_octets = cl;
285 }
286
287 domain_mkxrefs(domains, domains + num_domains - 1, 0);
288 memreq = domain_compactify(domains, num_domains);
289
290 blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN);
291 bsrc_end = memreq;
292 bsrc_start = (blocks - 1) * MAX_OPT_LEN;
293 bdst_start = bsrc_start + blocks * OPT_HEADER_LEN;
294 memreq += blocks * OPT_HEADER_LEN;
295
296 while (blocks--) {
297 size_t len = bsrc_end - bsrc_start;
298 memmove(result + bdst_start, result + bsrc_start, len);
299 result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH;
300 result[bdst_start - 1] = len;
301 bsrc_end = bsrc_start;
302 bsrc_start -= MAX_OPT_LEN;
303 bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN;
304 }
305
306 g_free(domains);
307 s->vdnssearch = result;
308 s->vdnssearch_len = memreq;
309 return 0;
310 }
+0
-213
vendor/libslirp/src/if.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #include "slirp.h"
6
7 static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
8 {
9 ifm->ifs_next = ifmhead->ifs_next;
10 ifmhead->ifs_next = ifm;
11 ifm->ifs_prev = ifmhead;
12 ifm->ifs_next->ifs_prev = ifm;
13 }
14
15 static void ifs_remque(struct mbuf *ifm)
16 {
17 ifm->ifs_prev->ifs_next = ifm->ifs_next;
18 ifm->ifs_next->ifs_prev = ifm->ifs_prev;
19 }
20
21 void if_init(Slirp *slirp)
22 {
23 slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;
24 slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;
25 }
26
27 /*
28 * if_output: Queue packet into an output queue.
29 * There are 2 output queue's, if_fastq and if_batchq.
30 * Each output queue is a doubly linked list of double linked lists
31 * of mbufs, each list belonging to one "session" (socket). This
32 * way, we can output packets fairly by sending one packet from each
33 * session, instead of all the packets from one session, then all packets
34 * from the next session, etc. Packets on the if_fastq get absolute
35 * priority, but if one session hogs the link, it gets "downgraded"
36 * to the batchq until it runs out of packets, then it'll return
37 * to the fastq (eg. if the user does an ls -alR in a telnet session,
38 * it'll temporarily get downgraded to the batchq)
39 */
40 void if_output(struct socket *so, struct mbuf *ifm)
41 {
42 Slirp *slirp = ifm->slirp;
43 struct mbuf *ifq;
44 int on_fastq = 1;
45
46 DEBUG_CALL("if_output");
47 DEBUG_ARG("so = %p", so);
48 DEBUG_ARG("ifm = %p", ifm);
49
50 /*
51 * First remove the mbuf from m_usedlist,
52 * since we're gonna use m_next and m_prev ourselves
53 * XXX Shouldn't need this, gotta change dtom() etc.
54 */
55 if (ifm->m_flags & M_USEDLIST) {
56 remque(ifm);
57 ifm->m_flags &= ~M_USEDLIST;
58 }
59
60 /*
61 * See if there's already a batchq list for this session.
62 * This can include an interactive session, which should go on fastq,
63 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
64 * We mustn't put this packet back on the fastq (or we'll send it out of
65 * order)
66 * XXX add cache here?
67 */
68 if (so) {
69 for (ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
70 (struct quehead *)ifq != &slirp->if_batchq; ifq = ifq->ifq_prev) {
71 if (so == ifq->ifq_so) {
72 /* A match! */
73 ifm->ifq_so = so;
74 ifs_insque(ifm, ifq->ifs_prev);
75 goto diddit;
76 }
77 }
78 }
79
80 /* No match, check which queue to put it on */
81 if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
82 ifq = (struct mbuf *)slirp->if_fastq.qh_rlink;
83 on_fastq = 1;
84 /*
85 * Check if this packet is a part of the last
86 * packet's session
87 */
88 if (ifq->ifq_so == so) {
89 ifm->ifq_so = so;
90 ifs_insque(ifm, ifq->ifs_prev);
91 goto diddit;
92 }
93 } else {
94 ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
95 }
96
97 /* Create a new doubly linked list for this session */
98 ifm->ifq_so = so;
99 ifs_init(ifm);
100 insque(ifm, ifq);
101
102 diddit:
103 if (so) {
104 /* Update *_queued */
105 so->so_queued++;
106 so->so_nqueued++;
107 /*
108 * Check if the interactive session should be downgraded to
109 * the batchq. A session is downgraded if it has queued 6
110 * packets without pausing, and at least 3 of those packets
111 * have been sent over the link
112 * (XXX These are arbitrary numbers, probably not optimal..)
113 */
114 if (on_fastq &&
115 ((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) {
116 /* Remove from current queue... */
117 remque(ifm->ifs_next);
118
119 /* ...And insert in the new. That'll teach ya! */
120 insque(ifm->ifs_next, &slirp->if_batchq);
121 }
122 }
123
124 /*
125 * This prevents us from malloc()ing too many mbufs
126 */
127 if_start(ifm->slirp);
128 }
129
130 /*
131 * Send one packet from each session.
132 * If there are packets on the fastq, they are sent FIFO, before
133 * everything else. Then we choose the first packet from each
134 * batchq session (socket) and send it.
135 * For example, if there are 3 ftp sessions fighting for bandwidth,
136 * one packet will be sent from the first session, then one packet
137 * from the second session, then one packet from the third.
138 */
139 void if_start(Slirp *slirp)
140 {
141 uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
142 bool from_batchq = false;
143 struct mbuf *ifm, *ifm_next, *ifqt;
144
145 DEBUG_CALL("if_start");
146
147 if (slirp->if_start_busy) {
148 return;
149 }
150 slirp->if_start_busy = true;
151
152 struct mbuf *batch_head = NULL;
153 if (slirp->if_batchq.qh_link != &slirp->if_batchq) {
154 batch_head = (struct mbuf *)slirp->if_batchq.qh_link;
155 }
156
157 if (slirp->if_fastq.qh_link != &slirp->if_fastq) {
158 ifm_next = (struct mbuf *)slirp->if_fastq.qh_link;
159 } else if (batch_head) {
160 /* Nothing on fastq, pick up from batchq */
161 ifm_next = batch_head;
162 from_batchq = true;
163 } else {
164 ifm_next = NULL;
165 }
166
167 while (ifm_next) {
168 ifm = ifm_next;
169
170 ifm_next = ifm->ifq_next;
171 if ((struct quehead *)ifm_next == &slirp->if_fastq) {
172 /* No more packets in fastq, switch to batchq */
173 ifm_next = batch_head;
174 from_batchq = true;
175 }
176 if ((struct quehead *)ifm_next == &slirp->if_batchq) {
177 /* end of batchq */
178 ifm_next = NULL;
179 }
180
181 /* Try to send packet unless it already expired */
182 if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
183 /* Packet is delayed due to pending ARP or NDP resolution */
184 continue;
185 }
186
187 /* Remove it from the queue */
188 ifqt = ifm->ifq_prev;
189 remque(ifm);
190
191 /* If there are more packets for this session, re-queue them */
192 if (ifm->ifs_next != ifm) {
193 struct mbuf *next = ifm->ifs_next;
194
195 insque(next, ifqt);
196 ifs_remque(ifm);
197 if (!from_batchq) {
198 ifm_next = next;
199 }
200 }
201
202 /* Update so_queued */
203 if (ifm->ifq_so && --ifm->ifq_so->so_queued == 0) {
204 /* If there's no more queued, reset nqueued */
205 ifm->ifq_so->so_nqueued = 0;
206 }
207
208 m_free(ifm);
209 }
210
211 slirp->if_start_busy = false;
212 }
+0
-25
vendor/libslirp/src/if.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #ifndef IF_H
6 #define IF_H
7
8 #define IF_COMPRESS 0x01 /* We want compression */
9 #define IF_NOCOMPRESS 0x02 /* Do not do compression */
10 #define IF_AUTOCOMP 0x04 /* Autodetect (default) */
11 #define IF_NOCIDCOMP 0x08 /* CID compression */
12
13 #define IF_MTU_DEFAULT 1500
14 #define IF_MTU_MIN 68
15 #define IF_MTU_MAX 65521
16 #define IF_MRU_DEFAULT 1500
17 #define IF_MRU_MIN 68
18 #define IF_MRU_MAX 65521
19 #define IF_COMP IF_AUTOCOMP /* Flags for compression */
20
21 /* 2 for alignment, 14 for ethernet */
22 #define IF_MAXLINKHDR (2 + ETH_HLEN)
23
24 #endif
+0
-242
vendor/libslirp/src/ip.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)ip.h 8.1 (Berkeley) 6/10/93
30 * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
31 */
32
33 #ifndef IP_H
34 #define IP_H
35
36 #include <glib.h>
37
38 #if G_BYTE_ORDER == G_BIG_ENDIAN
39 #undef NTOHL
40 #undef NTOHS
41 #undef HTONL
42 #undef HTONS
43 #define NTOHL(d)
44 #define NTOHS(d)
45 #define HTONL(d)
46 #define HTONS(d)
47 #else
48 #ifndef NTOHL
49 #define NTOHL(d) ((d) = ntohl((d)))
50 #endif
51 #ifndef NTOHS
52 #define NTOHS(d) ((d) = ntohs((uint16_t)(d)))
53 #endif
54 #ifndef HTONL
55 #define HTONL(d) ((d) = htonl((d)))
56 #endif
57 #ifndef HTONS
58 #define HTONS(d) ((d) = htons((uint16_t)(d)))
59 #endif
60 #endif
61
62 typedef uint32_t n_long; /* long as received from the net */
63
64 /*
65 * Definitions for internet protocol version 4.
66 * Per RFC 791, September 1981.
67 */
68 #define IPVERSION 4
69
70 /*
71 * Structure of an internet header, naked of options.
72 */
73 struct ip {
74 #if G_BYTE_ORDER == G_BIG_ENDIAN
75 uint8_t ip_v : 4, /* version */
76 ip_hl : 4; /* header length */
77 #else
78 uint8_t ip_hl : 4, /* header length */
79 ip_v : 4; /* version */
80 #endif
81 uint8_t ip_tos; /* type of service */
82 uint16_t ip_len; /* total length */
83 uint16_t ip_id; /* identification */
84 uint16_t ip_off; /* fragment offset field */
85 #define IP_DF 0x4000 /* don't fragment flag */
86 #define IP_MF 0x2000 /* more fragments flag */
87 #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
88 uint8_t ip_ttl; /* time to live */
89 uint8_t ip_p; /* protocol */
90 uint16_t ip_sum; /* checksum */
91 struct in_addr ip_src, ip_dst; /* source and dest address */
92 } SLIRP_PACKED;
93
94 #define IP_MAXPACKET 65535 /* maximum packet size */
95
96 /*
97 * Definitions for IP type of service (ip_tos)
98 */
99 #define IPTOS_LOWDELAY 0x10
100 #define IPTOS_THROUGHPUT 0x08
101 #define IPTOS_RELIABILITY 0x04
102
103 /*
104 * Definitions for options.
105 */
106 #define IPOPT_COPIED(o) ((o)&0x80)
107 #define IPOPT_CLASS(o) ((o)&0x60)
108 #define IPOPT_NUMBER(o) ((o)&0x1f)
109
110 #define IPOPT_CONTROL 0x00
111 #define IPOPT_RESERVED1 0x20
112 #define IPOPT_DEBMEAS 0x40
113 #define IPOPT_RESERVED2 0x60
114
115 #define IPOPT_EOL 0 /* end of option list */
116 #define IPOPT_NOP 1 /* no operation */
117
118 #define IPOPT_RR 7 /* record packet route */
119 #define IPOPT_TS 68 /* timestamp */
120 #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
121 #define IPOPT_LSRR 131 /* loose source route */
122 #define IPOPT_SATID 136 /* satnet id */
123 #define IPOPT_SSRR 137 /* strict source route */
124
125 /*
126 * Offsets to fields in options other than EOL and NOP.
127 */
128 #define IPOPT_OPTVAL 0 /* option ID */
129 #define IPOPT_OLEN 1 /* option length */
130 #define IPOPT_OFFSET 2 /* offset within option */
131 #define IPOPT_MINOFF 4 /* min value of above */
132
133 /*
134 * Time stamp option structure.
135 */
136 struct ip_timestamp {
137 uint8_t ipt_code; /* IPOPT_TS */
138 uint8_t ipt_len; /* size of structure (variable) */
139 uint8_t ipt_ptr; /* index of current entry */
140 #if G_BYTE_ORDER == G_BIG_ENDIAN
141 uint8_t ipt_oflw : 4, /* overflow counter */
142 ipt_flg : 4; /* flags, see below */
143 #else
144 uint8_t ipt_flg : 4, /* flags, see below */
145 ipt_oflw : 4; /* overflow counter */
146 #endif
147 union ipt_timestamp {
148 n_long ipt_time[1];
149 struct ipt_ta {
150 struct in_addr ipt_addr;
151 n_long ipt_time;
152 } ipt_ta[1];
153 } ipt_timestamp;
154 } SLIRP_PACKED;
155
156 /* flag bits for ipt_flg */
157 #define IPOPT_TS_TSONLY 0 /* timestamps only */
158 #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
159 #define IPOPT_TS_PRESPEC 3 /* specified modules only */
160
161 /* bits for security (not byte swapped) */
162 #define IPOPT_SECUR_UNCLASS 0x0000
163 #define IPOPT_SECUR_CONFID 0xf135
164 #define IPOPT_SECUR_EFTO 0x789a
165 #define IPOPT_SECUR_MMMM 0xbc4d
166 #define IPOPT_SECUR_RESTR 0xaf13
167 #define IPOPT_SECUR_SECRET 0xd788
168 #define IPOPT_SECUR_TOPSECRET 0x6bc5
169
170 /*
171 * Internet implementation parameters.
172 */
173 #define MAXTTL 255 /* maximum time to live (seconds) */
174 #define IPDEFTTL 64 /* default ttl, from RFC 1340 */
175 #define IPFRAGTTL 60 /* time to live for frags, slowhz */
176 #define IPTTLDEC 1 /* subtracted when forwarding */
177
178 #define IP_MSS 576 /* default maximum segment size */
179
180 #if GLIB_SIZEOF_VOID_P == 4
181 struct mbuf_ptr {
182 struct mbuf *mptr;
183 uint32_t dummy;
184 } SLIRP_PACKED;
185 #else
186 struct mbuf_ptr {
187 struct mbuf *mptr;
188 } SLIRP_PACKED;
189 #endif
190 struct qlink {
191 void *next, *prev;
192 };
193
194 /*
195 * Overlay for ip header used by other protocols (tcp, udp).
196 */
197 struct ipovly {
198 struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */
199 uint8_t ih_x1; /* (unused) */
200 uint8_t ih_pr; /* protocol */
201 uint16_t ih_len; /* protocol length */
202 struct in_addr ih_src; /* source internet address */
203 struct in_addr ih_dst; /* destination internet address */
204 } SLIRP_PACKED;
205
206 /*
207 * Ip reassembly queue structure. Each fragment
208 * being reassembled is attached to one of these structures.
209 * They are timed out after ipq_ttl drops to 0, and may also
210 * be reclaimed if memory becomes tight.
211 * size 28 bytes
212 */
213 struct ipq {
214 struct qlink frag_link; /* to ip headers of fragments */
215 struct qlink ip_link; /* to other reass headers */
216 uint8_t ipq_ttl; /* time for reass q to live */
217 uint8_t ipq_p; /* protocol of this fragment */
218 uint16_t ipq_id; /* sequence id for reassembly */
219 struct in_addr ipq_src, ipq_dst;
220 };
221
222 /*
223 * Ip header, when holding a fragment.
224 *
225 * Note: ipf_link must be at same offset as frag_link above
226 */
227 struct ipasfrag {
228 struct qlink ipf_link;
229 struct ip ipf_ip;
230 };
231
232 G_STATIC_ASSERT(offsetof(struct ipq, frag_link) ==
233 offsetof(struct ipasfrag, ipf_link));
234
235 #define ipf_off ipf_ip.ip_off
236 #define ipf_tos ipf_ip.ip_tos
237 #define ipf_len ipf_ip.ip_len
238 #define ipf_next ipf_link.next
239 #define ipf_prev ipf_link.prev
240
241 #endif
+0
-214
vendor/libslirp/src/ip6.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #ifndef SLIRP_IP6_H
7 #define SLIRP_IP6_H
8
9 #include <glib.h>
10 #include <string.h>
11
12 #define ALLNODES_MULTICAST \
13 { \
14 .s6_addr = { \
15 0xff, \
16 0x02, \
17 0x00, \
18 0x00, \
19 0x00, \
20 0x00, \
21 0x00, \
22 0x00, \
23 0x00, \
24 0x00, \
25 0x00, \
26 0x00, \
27 0x00, \
28 0x00, \
29 0x00, \
30 0x01 \
31 } \
32 }
33
34 #define SOLICITED_NODE_PREFIX \
35 { \
36 .s6_addr = { \
37 0xff, \
38 0x02, \
39 0x00, \
40 0x00, \
41 0x00, \
42 0x00, \
43 0x00, \
44 0x00, \
45 0x00, \
46 0x00, \
47 0x00, \
48 0x01, \
49 0xff, \
50 0x00, \
51 0x00, \
52 0x00 \
53 } \
54 }
55
56 #define LINKLOCAL_ADDR \
57 { \
58 .s6_addr = { \
59 0xfe, \
60 0x80, \
61 0x00, \
62 0x00, \
63 0x00, \
64 0x00, \
65 0x00, \
66 0x00, \
67 0x00, \
68 0x00, \
69 0x00, \
70 0x00, \
71 0x00, \
72 0x00, \
73 0x00, \
74 0x02 \
75 } \
76 }
77
78 #define ZERO_ADDR \
79 { \
80 .s6_addr = { \
81 0x00, \
82 0x00, \
83 0x00, \
84 0x00, \
85 0x00, \
86 0x00, \
87 0x00, \
88 0x00, \
89 0x00, \
90 0x00, \
91 0x00, \
92 0x00, \
93 0x00, \
94 0x00, \
95 0x00, \
96 0x00 \
97 } \
98 }
99
100 static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
101 {
102 return memcmp(a, b, sizeof(*a)) == 0;
103 }
104
105 static inline bool in6_equal_net(const struct in6_addr *a,
106 const struct in6_addr *b, int prefix_len)
107 {
108 if (memcmp(a, b, prefix_len / 8) != 0) {
109 return 0;
110 }
111
112 if (prefix_len % 8 == 0) {
113 return 1;
114 }
115
116 return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)) ==
117 b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
118 }
119
120 static inline bool in6_equal_mach(const struct in6_addr *a,
121 const struct in6_addr *b, int prefix_len)
122 {
123 if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
124 &(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
125 16 - DIV_ROUND_UP(prefix_len, 8)) != 0) {
126 return 0;
127 }
128
129 if (prefix_len % 8 == 0) {
130 return 1;
131 }
132
133 return (a->s6_addr[prefix_len / 8] &
134 ((1U << (8 - (prefix_len % 8))) - 1)) ==
135 (b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
136 }
137
138
139 #define in6_equal_router(a) \
140 ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
141 in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len)) || \
142 (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \
143 in6_equal_mach(a, &slirp->vhost_addr6, 64)))
144
145 #define in6_equal_dns(a) \
146 ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
147 in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len)) || \
148 (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \
149 in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))
150
151 #define in6_equal_host(a) (in6_equal_router(a) || in6_equal_dns(a))
152
153 #define in6_solicitednode_multicast(a) \
154 (in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104))
155
156 #define in6_zero(a) (in6_equal(a, &(struct in6_addr)ZERO_ADDR))
157
158 /* Compute emulated host MAC address from its ipv6 address */
159 static inline void in6_compute_ethaddr(struct in6_addr ip,
160 uint8_t eth[ETH_ALEN])
161 {
162 eth[0] = 0x52;
163 eth[1] = 0x56;
164 memcpy(&eth[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2);
165 }
166
167 /*
168 * Definitions for internet protocol version 6.
169 * Per RFC 2460, December 1998.
170 */
171 #define IP6VERSION 6
172 #define IP6_HOP_LIMIT 255
173
174 /*
175 * Structure of an internet header, naked of options.
176 */
177 struct ip6 {
178 #if G_BYTE_ORDER == G_BIG_ENDIAN
179 uint32_t ip_v : 4, /* version */
180 ip_tc_hi : 4, /* traffic class */
181 ip_tc_lo : 4, ip_fl_hi : 4, /* flow label */
182 ip_fl_lo : 16;
183 #else
184 uint32_t ip_tc_hi : 4, ip_v : 4, ip_fl_hi : 4, ip_tc_lo : 4, ip_fl_lo : 16;
185 #endif
186 uint16_t ip_pl; /* payload length */
187 uint8_t ip_nh; /* next header */
188 uint8_t ip_hl; /* hop limit */
189 struct in6_addr ip_src, ip_dst; /* source and dest address */
190 };
191
192 /*
193 * IPv6 pseudo-header used by upper-layer protocols
194 */
195 struct ip6_pseudohdr {
196 struct in6_addr ih_src; /* source internet address */
197 struct in6_addr ih_dst; /* destination internet address */
198 uint32_t ih_pl; /* upper-layer packet length */
199 uint16_t ih_zero_hi; /* zero */
200 uint8_t ih_zero_lo; /* zero */
201 uint8_t ih_nh; /* next header */
202 };
203
204 /*
205 * We don't want to mark these ip6 structs as packed as they are naturally
206 * correctly aligned; instead assert that there is no stray padding.
207 * If we marked the struct as packed then we would be unable to take
208 * the address of any of the fields in it.
209 */
210 G_STATIC_ASSERT(sizeof(struct ip6) == 40);
211 G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
212
213 #endif
+0
-434
vendor/libslirp/src/ip6_icmp.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #include "slirp.h"
7 #include "ip6_icmp.h"
8
9 #define NDP_Interval \
10 g_rand_int_range(slirp->grand, NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
11
12 static void ra_timer_handler(void *opaque)
13 {
14 Slirp *slirp = opaque;
15
16 slirp->cb->timer_mod(slirp->ra_timer,
17 slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
18 NDP_Interval,
19 slirp->opaque);
20 ndp_send_ra(slirp);
21 }
22
23 void icmp6_init(Slirp *slirp)
24 {
25 if (!slirp->in6_enabled) {
26 return;
27 }
28
29 slirp->ra_timer =
30 slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
31 slirp->cb->timer_mod(slirp->ra_timer,
32 slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
33 NDP_Interval,
34 slirp->opaque);
35 }
36
37 void icmp6_cleanup(Slirp *slirp)
38 {
39 if (!slirp->in6_enabled) {
40 return;
41 }
42
43 slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
44 }
45
46 static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
47 struct icmp6 *icmp)
48 {
49 struct mbuf *t = m_get(slirp);
50 t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
51 memcpy(t->m_data, m->m_data, t->m_len);
52
53 /* IPv6 Packet */
54 struct ip6 *rip = mtod(t, struct ip6 *);
55 rip->ip_dst = ip->ip_src;
56 rip->ip_src = ip->ip_dst;
57
58 /* ICMPv6 packet */
59 t->m_data += sizeof(struct ip6);
60 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
61 ricmp->icmp6_type = ICMP6_ECHO_REPLY;
62 ricmp->icmp6_cksum = 0;
63
64 /* Checksum */
65 t->m_data -= sizeof(struct ip6);
66 ricmp->icmp6_cksum = ip6_cksum(t);
67
68 ip6_output(NULL, t, 0);
69 }
70
71 void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
72 {
73 Slirp *slirp = m->slirp;
74 struct mbuf *t;
75 struct ip6 *ip = mtod(m, struct ip6 *);
76 char addrstr[INET6_ADDRSTRLEN];
77
78 DEBUG_CALL("icmp6_send_error");
79 DEBUG_ARG("type = %d, code = %d", type, code);
80
81 if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || in6_zero(&ip->ip_src)) {
82 /* TODO icmp error? */
83 return;
84 }
85
86 t = m_get(slirp);
87
88 /* IPv6 packet */
89 struct ip6 *rip = mtod(t, struct ip6 *);
90 rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
91 rip->ip_dst = ip->ip_src;
92 inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
93 DEBUG_ARG("target = %s", addrstr);
94
95 rip->ip_nh = IPPROTO_ICMPV6;
96 const int error_data_len = MIN(
97 m->m_len, slirp->if_mtu - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
98 rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
99 t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
100
101 /* ICMPv6 packet */
102 t->m_data += sizeof(struct ip6);
103 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
104 ricmp->icmp6_type = type;
105 ricmp->icmp6_code = code;
106 ricmp->icmp6_cksum = 0;
107
108 switch (type) {
109 case ICMP6_UNREACH:
110 case ICMP6_TIMXCEED:
111 ricmp->icmp6_err.unused = 0;
112 break;
113 case ICMP6_TOOBIG:
114 ricmp->icmp6_err.mtu = htonl(slirp->if_mtu);
115 break;
116 case ICMP6_PARAMPROB:
117 /* TODO: Handle this case */
118 break;
119 default:
120 g_assert_not_reached();
121 break;
122 }
123 t->m_data += ICMP6_ERROR_MINLEN;
124 memcpy(t->m_data, m->m_data, error_data_len);
125
126 /* Checksum */
127 t->m_data -= ICMP6_ERROR_MINLEN;
128 t->m_data -= sizeof(struct ip6);
129 ricmp->icmp6_cksum = ip6_cksum(t);
130
131 ip6_output(NULL, t, 0);
132 }
133
134 /*
135 * Send NDP Router Advertisement
136 */
137 void ndp_send_ra(Slirp *slirp)
138 {
139 DEBUG_CALL("ndp_send_ra");
140
141 /* Build IPv6 packet */
142 struct mbuf *t = m_get(slirp);
143 struct ip6 *rip = mtod(t, struct ip6 *);
144 size_t pl_size = 0;
145 struct in6_addr addr;
146 uint32_t scope_id;
147
148 rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
149 rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
150 rip->ip_nh = IPPROTO_ICMPV6;
151
152 /* Build ICMPv6 packet */
153 t->m_data += sizeof(struct ip6);
154 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
155 ricmp->icmp6_type = ICMP6_NDP_RA;
156 ricmp->icmp6_code = 0;
157 ricmp->icmp6_cksum = 0;
158
159 /* NDP */
160 ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
161 ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
162 ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
163 ricmp->icmp6_nra.reserved = 0;
164 ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
165 ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
166 ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
167 t->m_data += ICMP6_NDP_RA_MINLEN;
168 pl_size += ICMP6_NDP_RA_MINLEN;
169
170 /* Source link-layer address (NDP option) */
171 struct ndpopt *opt = mtod(t, struct ndpopt *);
172 opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
173 opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
174 in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
175 t->m_data += NDPOPT_LINKLAYER_LEN;
176 pl_size += NDPOPT_LINKLAYER_LEN;
177
178 /* Prefix information (NDP option) */
179 struct ndpopt *opt2 = mtod(t, struct ndpopt *);
180 opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
181 opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
182 opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
183 opt2->ndpopt_prefixinfo.L = 1;
184 opt2->ndpopt_prefixinfo.A = 1;
185 opt2->ndpopt_prefixinfo.reserved1 = 0;
186 opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
187 opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
188 opt2->ndpopt_prefixinfo.reserved2 = 0;
189 opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
190 t->m_data += NDPOPT_PREFIXINFO_LEN;
191 pl_size += NDPOPT_PREFIXINFO_LEN;
192
193 /* Prefix information (NDP option) */
194 if (get_dns6_addr(&addr, &scope_id) >= 0) {
195 /* Host system does have an IPv6 DNS server, announce our proxy. */
196 struct ndpopt *opt3 = mtod(t, struct ndpopt *);
197 opt3->ndpopt_type = NDPOPT_RDNSS;
198 opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
199 opt3->ndpopt_rdnss.reserved = 0;
200 opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
201 opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
202 t->m_data += NDPOPT_RDNSS_LEN;
203 pl_size += NDPOPT_RDNSS_LEN;
204 }
205
206 rip->ip_pl = htons(pl_size);
207 t->m_data -= sizeof(struct ip6) + pl_size;
208 t->m_len = sizeof(struct ip6) + pl_size;
209
210 /* ICMPv6 Checksum */
211 ricmp->icmp6_cksum = ip6_cksum(t);
212
213 ip6_output(NULL, t, 0);
214 }
215
216 /*
217 * Send NDP Neighbor Solitication
218 */
219 void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
220 {
221 char addrstr[INET6_ADDRSTRLEN];
222
223 inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
224
225 DEBUG_CALL("ndp_send_ns");
226 DEBUG_ARG("target = %s", addrstr);
227
228 /* Build IPv6 packet */
229 struct mbuf *t = m_get(slirp);
230 struct ip6 *rip = mtod(t, struct ip6 *);
231 rip->ip_src = slirp->vhost_addr6;
232 rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
233 memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
234 rip->ip_nh = IPPROTO_ICMPV6;
235 rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
236 t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
237
238 /* Build ICMPv6 packet */
239 t->m_data += sizeof(struct ip6);
240 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
241 ricmp->icmp6_type = ICMP6_NDP_NS;
242 ricmp->icmp6_code = 0;
243 ricmp->icmp6_cksum = 0;
244
245 /* NDP */
246 ricmp->icmp6_nns.reserved = 0;
247 ricmp->icmp6_nns.target = addr;
248
249 /* Build NDP option */
250 t->m_data += ICMP6_NDP_NS_MINLEN;
251 struct ndpopt *opt = mtod(t, struct ndpopt *);
252 opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
253 opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
254 in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
255
256 /* ICMPv6 Checksum */
257 t->m_data -= ICMP6_NDP_NA_MINLEN;
258 t->m_data -= sizeof(struct ip6);
259 ricmp->icmp6_cksum = ip6_cksum(t);
260
261 ip6_output(NULL, t, 1);
262 }
263
264 /*
265 * Send NDP Neighbor Advertisement
266 */
267 static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
268 {
269 /* Build IPv6 packet */
270 struct mbuf *t = m_get(slirp);
271 struct ip6 *rip = mtod(t, struct ip6 *);
272 rip->ip_src = icmp->icmp6_nns.target;
273 if (in6_zero(&ip->ip_src)) {
274 rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
275 } else {
276 rip->ip_dst = ip->ip_src;
277 }
278 rip->ip_nh = IPPROTO_ICMPV6;
279 rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN + NDPOPT_LINKLAYER_LEN);
280 t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
281
282 /* Build ICMPv6 packet */
283 t->m_data += sizeof(struct ip6);
284 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
285 ricmp->icmp6_type = ICMP6_NDP_NA;
286 ricmp->icmp6_code = 0;
287 ricmp->icmp6_cksum = 0;
288
289 /* NDP */
290 ricmp->icmp6_nna.R = NDP_IsRouter;
291 ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
292 ricmp->icmp6_nna.O = 1;
293 ricmp->icmp6_nna.reserved_hi = 0;
294 ricmp->icmp6_nna.reserved_lo = 0;
295 ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
296
297 /* Build NDP option */
298 t->m_data += ICMP6_NDP_NA_MINLEN;
299 struct ndpopt *opt = mtod(t, struct ndpopt *);
300 opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
301 opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
302 in6_compute_ethaddr(ricmp->icmp6_nna.target, opt->ndpopt_linklayer);
303
304 /* ICMPv6 Checksum */
305 t->m_data -= ICMP6_NDP_NA_MINLEN;
306 t->m_data -= sizeof(struct ip6);
307 ricmp->icmp6_cksum = ip6_cksum(t);
308
309 ip6_output(NULL, t, 0);
310 }
311
312 /*
313 * Process a NDP message
314 */
315 static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
316 struct icmp6 *icmp)
317 {
318 m->m_len += ETH_HLEN;
319 m->m_data -= ETH_HLEN;
320 struct ethhdr *eth = mtod(m, struct ethhdr *);
321 m->m_len -= ETH_HLEN;
322 m->m_data += ETH_HLEN;
323
324 switch (icmp->icmp6_type) {
325 case ICMP6_NDP_RS:
326 DEBUG_CALL(" type = Router Solicitation");
327 if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
328 ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
329 /* Gratuitous NDP */
330 ndp_table_add(slirp, ip->ip_src, eth->h_source);
331
332 ndp_send_ra(slirp);
333 }
334 break;
335
336 case ICMP6_NDP_RA:
337 DEBUG_CALL(" type = Router Advertisement");
338 slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
339 slirp->opaque);
340 break;
341
342 case ICMP6_NDP_NS:
343 DEBUG_CALL(" type = Neighbor Solicitation");
344 if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
345 !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target) &&
346 ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN &&
347 (!in6_zero(&ip->ip_src) ||
348 in6_solicitednode_multicast(&ip->ip_dst))) {
349 if (in6_equal_host(&icmp->icmp6_nns.target)) {
350 /* Gratuitous NDP */
351 ndp_table_add(slirp, ip->ip_src, eth->h_source);
352 ndp_send_na(slirp, ip, icmp);
353 }
354 }
355 break;
356
357 case ICMP6_NDP_NA:
358 DEBUG_CALL(" type = Neighbor Advertisement");
359 if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
360 ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN &&
361 !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target) &&
362 (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst) || icmp->icmp6_nna.S == 0)) {
363 ndp_table_add(slirp, ip->ip_src, eth->h_source);
364 }
365 break;
366
367 case ICMP6_NDP_REDIRECT:
368 DEBUG_CALL(" type = Redirect");
369 slirp->cb->guest_error(
370 "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
371 break;
372 }
373 }
374
375 /*
376 * Process a received ICMPv6 message.
377 */
378 void icmp6_input(struct mbuf *m)
379 {
380 struct icmp6 *icmp;
381 struct ip6 *ip = mtod(m, struct ip6 *);
382 Slirp *slirp = m->slirp;
383 int hlen = sizeof(struct ip6);
384
385 DEBUG_CALL("icmp6_input");
386 DEBUG_ARG("m = %p", m);
387 DEBUG_ARG("m_len = %d", m->m_len);
388
389 if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
390 goto end;
391 }
392
393 if (ip6_cksum(m)) {
394 goto end;
395 }
396
397 m->m_len -= hlen;
398 m->m_data += hlen;
399 icmp = mtod(m, struct icmp6 *);
400 m->m_len += hlen;
401 m->m_data -= hlen;
402
403 DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
404 switch (icmp->icmp6_type) {
405 case ICMP6_ECHO_REQUEST:
406 if (in6_equal_host(&ip->ip_dst)) {
407 icmp6_send_echoreply(m, slirp, ip, icmp);
408 } else {
409 /* TODO */
410 g_critical("external icmpv6 not supported yet");
411 }
412 break;
413
414 case ICMP6_NDP_RS:
415 case ICMP6_NDP_RA:
416 case ICMP6_NDP_NS:
417 case ICMP6_NDP_NA:
418 case ICMP6_NDP_REDIRECT:
419 ndp_input(m, slirp, ip, icmp);
420 break;
421
422 case ICMP6_UNREACH:
423 case ICMP6_TOOBIG:
424 case ICMP6_TIMXCEED:
425 case ICMP6_PARAMPROB:
426 /* XXX? report error? close socket? */
427 default:
428 break;
429 }
430
431 end:
432 m_free(m);
433 }
+0
-219
vendor/libslirp/src/ip6_icmp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #ifndef SLIRP_IP6_ICMP_H
7 #define SLIRP_IP6_ICMP_H
8
9 /*
10 * Interface Control Message Protocol version 6 Definitions.
11 * Per RFC 4443, March 2006.
12 *
13 * Network Discover Protocol Definitions.
14 * Per RFC 4861, September 2007.
15 */
16
17 struct icmp6_echo { /* Echo Messages */
18 uint16_t id;
19 uint16_t seq_num;
20 };
21
22 union icmp6_error_body {
23 uint32_t unused;
24 uint32_t pointer;
25 uint32_t mtu;
26 };
27
28 /*
29 * NDP Messages
30 */
31 struct ndp_rs { /* Router Solicitation Message */
32 uint32_t reserved;
33 };
34
35 struct ndp_ra { /* Router Advertisement Message */
36 uint8_t chl; /* Cur Hop Limit */
37 #if G_BYTE_ORDER == G_BIG_ENDIAN
38 uint8_t M : 1, O : 1, reserved : 6;
39 #else
40 uint8_t reserved : 6, O : 1, M : 1;
41 #endif
42 uint16_t lifetime; /* Router Lifetime */
43 uint32_t reach_time; /* Reachable Time */
44 uint32_t retrans_time; /* Retrans Timer */
45 };
46
47 G_STATIC_ASSERT(sizeof(struct ndp_ra) == 12);
48
49 struct ndp_ns { /* Neighbor Solicitation Message */
50 uint32_t reserved;
51 struct in6_addr target; /* Target Address */
52 };
53
54 G_STATIC_ASSERT(sizeof(struct ndp_ns) == 20);
55
56 struct ndp_na { /* Neighbor Advertisement Message */
57 #if G_BYTE_ORDER == G_BIG_ENDIAN
58 uint32_t R : 1, /* Router Flag */
59 S : 1, /* Solicited Flag */
60 O : 1, /* Override Flag */
61 reserved_hi : 5, reserved_lo : 24;
62 #else
63 uint32_t reserved_hi : 5, O : 1, S : 1, R : 1, reserved_lo : 24;
64 #endif
65 struct in6_addr target; /* Target Address */
66 };
67
68 G_STATIC_ASSERT(sizeof(struct ndp_na) == 20);
69
70 struct ndp_redirect {
71 uint32_t reserved;
72 struct in6_addr target; /* Target Address */
73 struct in6_addr dest; /* Destination Address */
74 };
75
76 G_STATIC_ASSERT(sizeof(struct ndp_redirect) == 36);
77
78 /*
79 * Structure of an icmpv6 header.
80 */
81 struct icmp6 {
82 uint8_t icmp6_type; /* type of message, see below */
83 uint8_t icmp6_code; /* type sub code */
84 uint16_t icmp6_cksum; /* ones complement cksum of struct */
85 union {
86 union icmp6_error_body error_body;
87 struct icmp6_echo echo;
88 struct ndp_rs ndp_rs;
89 struct ndp_ra ndp_ra;
90 struct ndp_ns ndp_ns;
91 struct ndp_na ndp_na;
92 struct ndp_redirect ndp_redirect;
93 } icmp6_body;
94 #define icmp6_err icmp6_body.error_body
95 #define icmp6_echo icmp6_body.echo
96 #define icmp6_nrs icmp6_body.ndp_rs
97 #define icmp6_nra icmp6_body.ndp_ra
98 #define icmp6_nns icmp6_body.ndp_ns
99 #define icmp6_nna icmp6_body.ndp_na
100 #define icmp6_redirect icmp6_body.ndp_redirect
101 };
102
103 G_STATIC_ASSERT(sizeof(struct icmp6) == 40);
104
105 #define ICMP6_MINLEN 4
106 #define ICMP6_ERROR_MINLEN 8
107 #define ICMP6_ECHO_MINLEN 8
108 #define ICMP6_NDP_RS_MINLEN 8
109 #define ICMP6_NDP_RA_MINLEN 16
110 #define ICMP6_NDP_NS_MINLEN 24
111 #define ICMP6_NDP_NA_MINLEN 24
112 #define ICMP6_NDP_REDIRECT_MINLEN 40
113
114 /*
115 * NDP Options
116 */
117 struct ndpopt {
118 uint8_t ndpopt_type; /* Option type */
119 uint8_t ndpopt_len; /* /!\ In units of 8 octets */
120 union {
121 unsigned char linklayer_addr[6]; /* Source/Target Link-layer */
122 #define ndpopt_linklayer ndpopt_body.linklayer_addr
123 struct prefixinfo { /* Prefix Information */
124 uint8_t prefix_length;
125 #if G_BYTE_ORDER == G_BIG_ENDIAN
126 uint8_t L : 1, A : 1, reserved1 : 6;
127 #else
128 uint8_t reserved1 : 6, A : 1, L : 1;
129 #endif
130 uint32_t valid_lt; /* Valid Lifetime */
131 uint32_t pref_lt; /* Preferred Lifetime */
132 uint32_t reserved2;
133 struct in6_addr prefix;
134 } SLIRP_PACKED prefixinfo;
135 #define ndpopt_prefixinfo ndpopt_body.prefixinfo
136 struct rdnss {
137 uint16_t reserved;
138 uint32_t lifetime;
139 struct in6_addr addr;
140 } SLIRP_PACKED rdnss;
141 #define ndpopt_rdnss ndpopt_body.rdnss
142 } ndpopt_body;
143 } SLIRP_PACKED;
144
145 /* NDP options type */
146 #define NDPOPT_LINKLAYER_SOURCE 1 /* Source Link-Layer Address */
147 #define NDPOPT_LINKLAYER_TARGET 2 /* Target Link-Layer Address */
148 #define NDPOPT_PREFIX_INFO 3 /* Prefix Information */
149 #define NDPOPT_RDNSS 25 /* Recursive DNS Server Address */
150
151 /* NDP options size, in octets. */
152 #define NDPOPT_LINKLAYER_LEN 8
153 #define NDPOPT_PREFIXINFO_LEN 32
154 #define NDPOPT_RDNSS_LEN 24
155
156 /*
157 * Definition of type and code field values.
158 * Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
159 * Last Updated 2012-11-12
160 */
161
162 /* Errors */
163 #define ICMP6_UNREACH 1 /* Destination Unreachable */
164 #define ICMP6_UNREACH_NO_ROUTE 0 /* no route to dest */
165 #define ICMP6_UNREACH_DEST_PROHIB 1 /* com with dest prohibited */
166 #define ICMP6_UNREACH_SCOPE 2 /* beyond scope of src addr */
167 #define ICMP6_UNREACH_ADDRESS 3 /* address unreachable */
168 #define ICMP6_UNREACH_PORT 4 /* port unreachable */
169 #define ICMP6_UNREACH_SRC_FAIL 5 /* src addr failed */
170 #define ICMP6_UNREACH_REJECT_ROUTE 6 /* reject route to dest */
171 #define ICMP6_UNREACH_SRC_HDR_ERROR 7 /* error in src routing header */
172 #define ICMP6_TOOBIG 2 /* Packet Too Big */
173 #define ICMP6_TIMXCEED 3 /* Time Exceeded */
174 #define ICMP6_TIMXCEED_INTRANS 0 /* hop limit exceeded in transit */
175 #define ICMP6_TIMXCEED_REASS 1 /* ttl=0 in reass */
176 #define ICMP6_PARAMPROB 4 /* Parameter Problem */
177 #define ICMP6_PARAMPROB_HDR_FIELD 0 /* err header field */
178 #define ICMP6_PARAMPROB_NXTHDR_TYPE 1 /* unrecognized Next Header type */
179 #define ICMP6_PARAMPROB_IPV6_OPT 2 /* unrecognized IPv6 option */
180
181 /* Informational Messages */
182 #define ICMP6_ECHO_REQUEST 128 /* Echo Request */
183 #define ICMP6_ECHO_REPLY 129 /* Echo Reply */
184 #define ICMP6_NDP_RS 133 /* Router Solicitation (NDP) */
185 #define ICMP6_NDP_RA 134 /* Router Advertisement (NDP) */
186 #define ICMP6_NDP_NS 135 /* Neighbor Solicitation (NDP) */
187 #define ICMP6_NDP_NA 136 /* Neighbor Advertisement (NDP) */
188 #define ICMP6_NDP_REDIRECT 137 /* Redirect Message (NDP) */
189
190 /*
191 * Router Configuration Variables (rfc4861#section-6)
192 */
193 #define NDP_IsRouter 1
194 #define NDP_AdvSendAdvertisements 1
195 #define NDP_MaxRtrAdvInterval 600000
196 #define NDP_MinRtrAdvInterval \
197 ((NDP_MaxRtrAdvInterval >= 9) ? NDP_MaxRtrAdvInterval / 3 : \
198 NDP_MaxRtrAdvInterval)
199 #define NDP_AdvManagedFlag 0
200 #define NDP_AdvOtherConfigFlag 0
201 #define NDP_AdvLinkMTU 0
202 #define NDP_AdvReachableTime 0
203 #define NDP_AdvRetransTime 0
204 #define NDP_AdvCurHopLimit 64
205 #define NDP_AdvDefaultLifetime ((3 * NDP_MaxRtrAdvInterval) / 1000)
206 #define NDP_AdvValidLifetime 86400
207 #define NDP_AdvOnLinkFlag 1
208 #define NDP_AdvPrefLifetime 14400
209 #define NDP_AdvAutonomousFlag 1
210
211 void icmp6_init(Slirp *slirp);
212 void icmp6_cleanup(Slirp *slirp);
213 void icmp6_input(struct mbuf *);
214 void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code);
215 void ndp_send_ra(Slirp *slirp);
216 void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
217
218 #endif
+0
-78
vendor/libslirp/src/ip6_input.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #include "slirp.h"
7 #include "ip6_icmp.h"
8
9 /*
10 * IP initialization: fill in IP protocol switch table.
11 * All protocols not implemented in kernel go to raw IP protocol handler.
12 */
13 void ip6_init(Slirp *slirp)
14 {
15 icmp6_init(slirp);
16 }
17
18 void ip6_cleanup(Slirp *slirp)
19 {
20 icmp6_cleanup(slirp);
21 }
22
23 void ip6_input(struct mbuf *m)
24 {
25 struct ip6 *ip6;
26 Slirp *slirp = m->slirp;
27
28 if (!slirp->in6_enabled) {
29 goto bad;
30 }
31
32 DEBUG_CALL("ip6_input");
33 DEBUG_ARG("m = %p", m);
34 DEBUG_ARG("m_len = %d", m->m_len);
35
36 if (m->m_len < sizeof(struct ip6)) {
37 goto bad;
38 }
39
40 ip6 = mtod(m, struct ip6 *);
41
42 if (ip6->ip_v != IP6VERSION) {
43 goto bad;
44 }
45
46 if (ntohs(ip6->ip_pl) > slirp->if_mtu) {
47 icmp6_send_error(m, ICMP6_TOOBIG, 0);
48 goto bad;
49 }
50
51 /* check ip_ttl for a correct ICMP reply */
52 if (ip6->ip_hl == 0) {
53 icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
54 goto bad;
55 }
56
57 /*
58 * Switch out to protocol's input routine.
59 */
60 switch (ip6->ip_nh) {
61 case IPPROTO_TCP:
62 NTOHS(ip6->ip_pl);
63 tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6);
64 break;
65 case IPPROTO_UDP:
66 udp6_input(m);
67 break;
68 case IPPROTO_ICMPV6:
69 icmp6_input(m);
70 break;
71 default:
72 m_free(m);
73 }
74 return;
75 bad:
76 m_free(m);
77 }
+0
-39
vendor/libslirp/src/ip6_output.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #include "slirp.h"
7
8 /* Number of packets queued before we start sending
9 * (to prevent allocing too many mbufs) */
10 #define IF6_THRESH 10
11
12 /*
13 * IPv6 output. The packet in mbuf chain m contains a IP header
14 */
15 int ip6_output(struct socket *so, struct mbuf *m, int fast)
16 {
17 struct ip6 *ip = mtod(m, struct ip6 *);
18
19 DEBUG_CALL("ip6_output");
20 DEBUG_ARG("so = %p", so);
21 DEBUG_ARG("m = %p", m);
22
23 /* Fill IPv6 header */
24 ip->ip_v = IP6VERSION;
25 ip->ip_hl = IP6_HOP_LIMIT;
26 ip->ip_tc_hi = 0;
27 ip->ip_tc_lo = 0;
28 ip->ip_fl_hi = 0;
29 ip->ip_fl_lo = 0;
30
31 if (fast) {
32 if_encap(m->slirp, m);
33 } else {
34 if_output(so, m);
35 }
36
37 return 0;
38 }
+0
-482
vendor/libslirp/src/ip_icmp.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
30 * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
31 */
32
33 #include "slirp.h"
34 #include "ip_icmp.h"
35
36 #ifndef WITH_ICMP_ERROR_MSG
37 #define WITH_ICMP_ERROR_MSG 0
38 #endif
39
40 /* The message sent when emulating PING */
41 /* Be nice and tell them it's just a pseudo-ping packet */
42 static const char icmp_ping_msg[] =
43 "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST "
44 "packets.\n";
45
46 /* list of actions for icmp_send_error() on RX of an icmp message */
47 static const int icmp_flush[19] = {
48 /* ECHO REPLY (0) */ 0,
49 1,
50 1,
51 /* DEST UNREACH (3) */ 1,
52 /* SOURCE QUENCH (4)*/ 1,
53 /* REDIRECT (5) */ 1,
54 1,
55 1,
56 /* ECHO (8) */ 0,
57 /* ROUTERADVERT (9) */ 1,
58 /* ROUTERSOLICIT (10) */ 1,
59 /* TIME EXCEEDED (11) */ 1,
60 /* PARAMETER PROBLEM (12) */ 1,
61 /* TIMESTAMP (13) */ 0,
62 /* TIMESTAMP REPLY (14) */ 0,
63 /* INFO (15) */ 0,
64 /* INFO REPLY (16) */ 0,
65 /* ADDR MASK (17) */ 0,
66 /* ADDR MASK REPLY (18) */ 0
67 };
68
69 void icmp_init(Slirp *slirp)
70 {
71 slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
72 slirp->icmp_last_so = &slirp->icmp;
73 }
74
75 void icmp_cleanup(Slirp *slirp)
76 {
77 while (slirp->icmp.so_next != &slirp->icmp) {
78 icmp_detach(slirp->icmp.so_next);
79 }
80 }
81
82 static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
83 {
84 struct ip *ip = mtod(m, struct ip *);
85 struct sockaddr_in addr;
86
87 so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
88 if (so->s == -1) {
89 return -1;
90 }
91
92 so->so_m = m;
93 so->so_faddr = ip->ip_dst;
94 so->so_laddr = ip->ip_src;
95 so->so_iptos = ip->ip_tos;
96 so->so_type = IPPROTO_ICMP;
97 so->so_state = SS_ISFCONNECTED;
98 so->so_expire = curtime + SO_EXPIRE;
99
100 addr.sin_family = AF_INET;
101 addr.sin_addr = so->so_faddr;
102
103 insque(so, &so->slirp->icmp);
104
105 if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
106 (struct sockaddr *)&addr, sizeof(addr)) == -1) {
107 DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s", errno,
108 strerror(errno));
109 icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
110 icmp_detach(so);
111 }
112
113 return 0;
114 }
115
116 void icmp_detach(struct socket *so)
117 {
118 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
119 closesocket(so->s);
120 sofree(so);
121 }
122
123 /*
124 * Process a received ICMP message.
125 */
126 void icmp_input(struct mbuf *m, int hlen)
127 {
128 register struct icmp *icp;
129 register struct ip *ip = mtod(m, struct ip *);
130 int icmplen = ip->ip_len;
131 Slirp *slirp = m->slirp;
132
133 DEBUG_CALL("icmp_input");
134 DEBUG_ARG("m = %p", m);
135 DEBUG_ARG("m_len = %d", m->m_len);
136
137 /*
138 * Locate icmp structure in mbuf, and check
139 * that its not corrupted and of at least minimum length.
140 */
141 if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
142 freeit:
143 m_free(m);
144 goto end_error;
145 }
146
147 m->m_len -= hlen;
148 m->m_data += hlen;
149 icp = mtod(m, struct icmp *);
150 if (cksum(m, icmplen)) {
151 goto freeit;
152 }
153 m->m_len += hlen;
154 m->m_data -= hlen;
155
156 DEBUG_ARG("icmp_type = %d", icp->icmp_type);
157 switch (icp->icmp_type) {
158 case ICMP_ECHO:
159 ip->ip_len += hlen; /* since ip_input subtracts this */
160 if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
161 ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) {
162 icmp_reflect(m);
163 } else if (slirp->restricted) {
164 goto freeit;
165 } else {
166 struct socket *so;
167 struct sockaddr_storage addr;
168 so = socreate(slirp);
169 if (icmp_send(so, m, hlen) == 0) {
170 return;
171 }
172 if (udp_attach(so, AF_INET) == -1) {
173 DEBUG_MISC("icmp_input udp_attach errno = %d-%s", errno,
174 strerror(errno));
175 sofree(so);
176 m_free(m);
177 goto end_error;
178 }
179 so->so_m = m;
180 so->so_ffamily = AF_INET;
181 so->so_faddr = ip->ip_dst;
182 so->so_fport = htons(7);
183 so->so_lfamily = AF_INET;
184 so->so_laddr = ip->ip_src;
185 so->so_lport = htons(9);
186 so->so_iptos = ip->ip_tos;
187 so->so_type = IPPROTO_ICMP;
188 so->so_state = SS_ISFCONNECTED;
189
190 /* Send the packet */
191 addr = so->fhost.ss;
192 if (sotranslate_out(so, &addr) < 0) {
193 icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
194 strerror(errno));
195 udp_detach(so);
196 return;
197 }
198
199 if (sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
200 (struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
201 DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s", errno,
202 strerror(errno));
203 icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
204 strerror(errno));
205 udp_detach(so);
206 }
207 } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
208 break;
209 case ICMP_UNREACH:
210 /* XXX? report error? close socket? */
211 case ICMP_TIMXCEED:
212 case ICMP_PARAMPROB:
213 case ICMP_SOURCEQUENCH:
214 case ICMP_TSTAMP:
215 case ICMP_MASKREQ:
216 case ICMP_REDIRECT:
217 m_free(m);
218 break;
219
220 default:
221 m_free(m);
222 } /* swith */
223
224 end_error:
225 /* m is m_free()'d xor put in a socket xor or given to ip_send */
226 return;
227 }
228
229
230 /*
231 * Send an ICMP message in response to a situation
232 *
233 * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header.
234 *MAY send more (we do). MUST NOT change this header information. MUST NOT reply
235 *to a multicast/broadcast IP address. MUST NOT reply to a multicast/broadcast
236 *MAC address. MUST reply to only the first fragment.
237 */
238 /*
239 * Send ICMP_UNREACH back to the source regarding msrc.
240 * mbuf *msrc is used as a template, but is NOT m_free()'d.
241 * It is reported as the bad ip packet. The header should
242 * be fully correct and in host byte order.
243 * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
244 * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
245 */
246
247 #define ICMP_MAXDATALEN (IP_MSS - 28)
248 void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
249 const char *message)
250 {
251 unsigned hlen, shlen, s_ip_len;
252 register struct ip *ip;
253 register struct icmp *icp;
254 register struct mbuf *m;
255
256 DEBUG_CALL("icmp_send_error");
257 DEBUG_ARG("msrc = %p", msrc);
258 DEBUG_ARG("msrc_len = %d", msrc->m_len);
259
260 if (type != ICMP_UNREACH && type != ICMP_TIMXCEED)
261 goto end_error;
262
263 /* check msrc */
264 if (!msrc)
265 goto end_error;
266 ip = mtod(msrc, struct ip *);
267 if (slirp_debug & DBG_MISC) {
268 char bufa[20], bufb[20];
269 strcpy(bufa, inet_ntoa(ip->ip_src));
270 strcpy(bufb, inet_ntoa(ip->ip_dst));
271 DEBUG_MISC(" %.16s to %.16s", bufa, bufb);
272 }
273 if (ip->ip_off & IP_OFFMASK)
274 goto end_error; /* Only reply to fragment 0 */
275
276 /* Do not reply to source-only IPs */
277 if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
278 goto end_error;
279 }
280
281 shlen = ip->ip_hl << 2;
282 s_ip_len = ip->ip_len;
283 if (ip->ip_p == IPPROTO_ICMP) {
284 icp = (struct icmp *)((char *)ip + shlen);
285 /*
286 * Assume any unknown ICMP type is an error. This isn't
287 * specified by the RFC, but think about it..
288 */
289 if (icp->icmp_type > 18 || icmp_flush[icp->icmp_type])
290 goto end_error;
291 }
292
293 /* make a copy */
294 m = m_get(msrc->slirp);
295 if (!m) {
296 goto end_error;
297 }
298
299 {
300 int new_m_size;
301 new_m_size =
302 sizeof(struct ip) + ICMP_MINLEN + msrc->m_len + ICMP_MAXDATALEN;
303 if (new_m_size > m->m_size)
304 m_inc(m, new_m_size);
305 }
306 memcpy(m->m_data, msrc->m_data, msrc->m_len);
307 m->m_len = msrc->m_len; /* copy msrc to m */
308
309 /* make the header of the reply packet */
310 ip = mtod(m, struct ip *);
311 hlen = sizeof(struct ip); /* no options in reply */
312
313 /* fill in icmp */
314 m->m_data += hlen;
315 m->m_len -= hlen;
316
317 icp = mtod(m, struct icmp *);
318
319 if (minsize)
320 s_ip_len = shlen + ICMP_MINLEN; /* return header+8b only */
321 else if (s_ip_len > ICMP_MAXDATALEN) /* maximum size */
322 s_ip_len = ICMP_MAXDATALEN;
323
324 m->m_len = ICMP_MINLEN + s_ip_len; /* 8 bytes ICMP header */
325
326 /* min. size = 8+sizeof(struct ip)+8 */
327
328 icp->icmp_type = type;
329 icp->icmp_code = code;
330 icp->icmp_id = 0;
331 icp->icmp_seq = 0;
332
333 memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
334 HTONS(icp->icmp_ip.ip_len);
335 HTONS(icp->icmp_ip.ip_id);
336 HTONS(icp->icmp_ip.ip_off);
337
338 if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */
339 int message_len;
340 char *cpnt;
341 message_len = strlen(message);
342 if (message_len > ICMP_MAXDATALEN)
343 message_len = ICMP_MAXDATALEN;
344 cpnt = (char *)m->m_data + m->m_len;
345 memcpy(cpnt, message, message_len);
346 m->m_len += message_len;
347 }
348
349 icp->icmp_cksum = 0;
350 icp->icmp_cksum = cksum(m, m->m_len);
351
352 m->m_data -= hlen;
353 m->m_len += hlen;
354
355 /* fill in ip */
356 ip->ip_hl = hlen >> 2;
357 ip->ip_len = m->m_len;
358
359 ip->ip_tos = ((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
360
361 ip->ip_ttl = MAXTTL;
362 ip->ip_p = IPPROTO_ICMP;
363 ip->ip_dst = ip->ip_src; /* ip addresses */
364 ip->ip_src = m->slirp->vhost_addr;
365
366 (void)ip_output((struct socket *)NULL, m);
367
368 end_error:
369 return;
370 }
371 #undef ICMP_MAXDATALEN
372
373 /*
374 * Reflect the ip packet back to the source
375 */
376 void icmp_reflect(struct mbuf *m)
377 {
378 register struct ip *ip = mtod(m, struct ip *);
379 int hlen = ip->ip_hl << 2;
380 int optlen = hlen - sizeof(struct ip);
381 register struct icmp *icp;
382
383 /*
384 * Send an icmp packet back to the ip level,
385 * after supplying a checksum.
386 */
387 m->m_data += hlen;
388 m->m_len -= hlen;
389 icp = mtod(m, struct icmp *);
390
391 icp->icmp_type = ICMP_ECHOREPLY;
392 icp->icmp_cksum = 0;
393 icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
394
395 m->m_data -= hlen;
396 m->m_len += hlen;
397
398 /* fill in ip */
399 if (optlen > 0) {
400 /*
401 * Strip out original options by copying rest of first
402 * mbuf's data back, and adjust the IP length.
403 */
404 memmove((char *)(ip + 1), (char *)ip + hlen,
405 (unsigned)(m->m_len - hlen));
406 hlen -= optlen;
407 ip->ip_hl = hlen >> 2;
408 ip->ip_len -= optlen;
409 m->m_len -= optlen;
410 }
411
412 ip->ip_ttl = MAXTTL;
413 { /* swap */
414 struct in_addr icmp_dst;
415 icmp_dst = ip->ip_dst;
416 ip->ip_dst = ip->ip_src;
417 ip->ip_src = icmp_dst;
418 }
419
420 (void)ip_output((struct socket *)NULL, m);
421 }
422
423 void icmp_receive(struct socket *so)
424 {
425 struct mbuf *m = so->so_m;
426 struct ip *ip = mtod(m, struct ip *);
427 int hlen = ip->ip_hl << 2;
428 uint8_t error_code;
429 struct icmp *icp;
430 int id, len;
431
432 m->m_data += hlen;
433 m->m_len -= hlen;
434 icp = mtod(m, struct icmp *);
435
436 id = icp->icmp_id;
437 len = recv(so->s, icp, M_ROOM(m), 0);
438 /*
439 * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
440 * between host OSes. On Linux, only the ICMP header and payload is
441 * included. On macOS/Darwin, the socket acts like a raw socket and
442 * includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
443 * sockets aren't supported at all, so we treat them like raw sockets. It
444 * isn't possible to detect this difference at runtime, so we must use an
445 * #ifdef to determine if we need to remove the IP header.
446 */
447 #ifdef CONFIG_BSD
448 if (len >= sizeof(struct ip)) {
449 struct ip *inner_ip = mtod(m, struct ip *);
450 int inner_hlen = inner_ip->ip_hl << 2;
451 if (inner_hlen > len) {
452 len = -1;
453 errno = -EINVAL;
454 } else {
455 len -= inner_hlen;
456 memmove(icp, (unsigned char *)icp + inner_hlen, len);
457 }
458 } else {
459 len = -1;
460 errno = -EINVAL;
461 }
462 #endif
463 icp->icmp_id = id;
464
465 m->m_data -= hlen;
466 m->m_len += hlen;
467
468 if (len == -1 || len == 0) {
469 if (errno == ENETUNREACH) {
470 error_code = ICMP_UNREACH_NET;
471 } else {
472 error_code = ICMP_UNREACH_HOST;
473 }
474 DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno));
475 icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
476 } else {
477 icmp_reflect(so->so_m);
478 so->so_m = NULL; /* Don't m_free() it again! */
479 }
480 icmp_detach(so);
481 }
+0
-166
vendor/libslirp/src/ip_icmp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
30 * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
31 */
32
33 #ifndef NETINET_IP_ICMP_H
34 #define NETINET_IP_ICMP_H
35
36 /*
37 * Interface Control Message Protocol Definitions.
38 * Per RFC 792, September 1981.
39 */
40
41 typedef uint32_t n_time;
42
43 /*
44 * Structure of an icmp header.
45 */
46 struct icmp {
47 uint8_t icmp_type; /* type of message, see below */
48 uint8_t icmp_code; /* type sub code */
49 uint16_t icmp_cksum; /* ones complement cksum of struct */
50 union {
51 uint8_t ih_pptr; /* ICMP_PARAMPROB */
52 struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
53 struct ih_idseq {
54 uint16_t icd_id;
55 uint16_t icd_seq;
56 } ih_idseq;
57 int ih_void;
58
59 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
60 struct ih_pmtu {
61 uint16_t ipm_void;
62 uint16_t ipm_nextmtu;
63 } ih_pmtu;
64 } icmp_hun;
65 #define icmp_pptr icmp_hun.ih_pptr
66 #define icmp_gwaddr icmp_hun.ih_gwaddr
67 #define icmp_id icmp_hun.ih_idseq.icd_id
68 #define icmp_seq icmp_hun.ih_idseq.icd_seq
69 #define icmp_void icmp_hun.ih_void
70 #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
71 #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
72 union {
73 struct id_ts {
74 n_time its_otime;
75 n_time its_rtime;
76 n_time its_ttime;
77 } id_ts;
78 struct id_ip {
79 struct ip idi_ip;
80 /* options and then 64 bits of data */
81 } id_ip;
82 uint32_t id_mask;
83 char id_data[1];
84 } icmp_dun;
85 #define icmp_otime icmp_dun.id_ts.its_otime
86 #define icmp_rtime icmp_dun.id_ts.its_rtime
87 #define icmp_ttime icmp_dun.id_ts.its_ttime
88 #define icmp_ip icmp_dun.id_ip.idi_ip
89 #define icmp_mask icmp_dun.id_mask
90 #define icmp_data icmp_dun.id_data
91 };
92
93 /*
94 * Lower bounds on packet lengths for various types.
95 * For the error advice packets must first ensure that the
96 * packet is large enough to contain the returned ip header.
97 * Only then can we do the check to see if 64 bits of packet
98 * data have been returned, since we need to check the returned
99 * ip header length.
100 */
101 #define ICMP_MINLEN 8 /* abs minimum */
102 #define ICMP_TSLEN (8 + 3 * sizeof(n_time)) /* timestamp */
103 #define ICMP_MASKLEN 12 /* address mask */
104 #define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) /* min */
105 #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
106 /* N.B.: must separately check that ip_hl >= 5 */
107
108 /*
109 * Definition of type and code field values.
110 */
111 #define ICMP_ECHOREPLY 0 /* echo reply */
112 #define ICMP_UNREACH 3 /* dest unreachable, codes: */
113 #define ICMP_UNREACH_NET 0 /* bad net */
114 #define ICMP_UNREACH_HOST 1 /* bad host */
115 #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
116 #define ICMP_UNREACH_PORT 3 /* bad port */
117 #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
118 #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
119 #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
120 #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
121 #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
122 #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
123 #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
124 #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
125 #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
126 #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
127 #define ICMP_REDIRECT 5 /* shorter route, codes: */
128 #define ICMP_REDIRECT_NET 0 /* for network */
129 #define ICMP_REDIRECT_HOST 1 /* for host */
130 #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
131 #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
132 #define ICMP_ECHO 8 /* echo service */
133 #define ICMP_ROUTERADVERT 9 /* router advertisement */
134 #define ICMP_ROUTERSOLICIT 10 /* router solicitation */
135 #define ICMP_TIMXCEED 11 /* time exceeded, code: */
136 #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
137 #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
138 #define ICMP_PARAMPROB 12 /* ip header bad */
139 #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
140 #define ICMP_TSTAMP 13 /* timestamp request */
141 #define ICMP_TSTAMPREPLY 14 /* timestamp reply */
142 #define ICMP_IREQ 15 /* information request */
143 #define ICMP_IREQREPLY 16 /* information reply */
144 #define ICMP_MASKREQ 17 /* address mask request */
145 #define ICMP_MASKREPLY 18 /* address mask reply */
146
147 #define ICMP_MAXTYPE 18
148
149 #define ICMP_INFOTYPE(type) \
150 ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
151 (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
152 (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
153 (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
154 (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
155
156 void icmp_init(Slirp *slirp);
157 void icmp_cleanup(Slirp *slirp);
158 void icmp_input(struct mbuf *, int);
159 void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
160 const char *message);
161 void icmp_reflect(struct mbuf *);
162 void icmp_receive(struct socket *so);
163 void icmp_detach(struct socket *so);
164
165 #endif
+0
-461
vendor/libslirp/src/ip_input.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)ip_input.c 8.2 (Berkeley) 1/4/94
30 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP are
35 * Copyright (c) 1995 Danny Gasparovski.
36 */
37
38 #include "slirp.h"
39 #include "ip_icmp.h"
40
41 static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
42 static void ip_freef(Slirp *slirp, struct ipq *fp);
43 static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev);
44 static void ip_deq(register struct ipasfrag *p);
45
46 /*
47 * IP initialization: fill in IP protocol switch table.
48 * All protocols not implemented in kernel go to raw IP protocol handler.
49 */
50 void ip_init(Slirp *slirp)
51 {
52 slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
53 udp_init(slirp);
54 tcp_init(slirp);
55 icmp_init(slirp);
56 }
57
58 void ip_cleanup(Slirp *slirp)
59 {
60 udp_cleanup(slirp);
61 tcp_cleanup(slirp);
62 icmp_cleanup(slirp);
63 }
64
65 /*
66 * Ip input routine. Checksum and byte swap header. If fragmented
67 * try to reassemble. Process options. Pass to next level.
68 */
69 void ip_input(struct mbuf *m)
70 {
71 Slirp *slirp = m->slirp;
72 register struct ip *ip;
73 int hlen;
74
75 if (!slirp->in_enabled) {
76 goto bad;
77 }
78
79 DEBUG_CALL("ip_input");
80 DEBUG_ARG("m = %p", m);
81 DEBUG_ARG("m_len = %d", m->m_len);
82
83 if (m->m_len < sizeof(struct ip)) {
84 goto bad;
85 }
86
87 ip = mtod(m, struct ip *);
88
89 if (ip->ip_v != IPVERSION) {
90 goto bad;
91 }
92
93 hlen = ip->ip_hl << 2;
94 if (hlen < sizeof(struct ip) || hlen > m->m_len) { /* min header length */
95 goto bad; /* or packet too short */
96 }
97
98 /* keep ip header intact for ICMP reply
99 * ip->ip_sum = cksum(m, hlen);
100 * if (ip->ip_sum) {
101 */
102 if (cksum(m, hlen)) {
103 goto bad;
104 }
105
106 /*
107 * Convert fields to host representation.
108 */
109 NTOHS(ip->ip_len);
110 if (ip->ip_len < hlen) {
111 goto bad;
112 }
113 NTOHS(ip->ip_id);
114 NTOHS(ip->ip_off);
115
116 /*
117 * Check that the amount of data in the buffers
118 * is as at least much as the IP header would have us expect.
119 * Trim mbufs if longer than we expect.
120 * Drop packet if shorter than we expect.
121 */
122 if (m->m_len < ip->ip_len) {
123 goto bad;
124 }
125
126 /* Should drop packet if mbuf too long? hmmm... */
127 if (m->m_len > ip->ip_len)
128 m_adj(m, ip->ip_len - m->m_len);
129
130 /* check ip_ttl for a correct ICMP reply */
131 if (ip->ip_ttl == 0) {
132 icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
133 goto bad;
134 }
135
136 /*
137 * If offset or IP_MF are set, must reassemble.
138 * Otherwise, nothing need be done.
139 * (We could look in the reassembly queue to see
140 * if the packet was previously fragmented,
141 * but it's not worth the time; just let them time out.)
142 *
143 * XXX This should fail, don't fragment yet
144 */
145 if (ip->ip_off & ~IP_DF) {
146 register struct ipq *fp;
147 struct qlink *l;
148 /*
149 * Look for queue of fragments
150 * of this datagram.
151 */
152 for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
153 l = l->next) {
154 fp = container_of(l, struct ipq, ip_link);
155 if (ip->ip_id == fp->ipq_id &&
156 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
157 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
158 ip->ip_p == fp->ipq_p)
159 goto found;
160 }
161 fp = NULL;
162 found:
163
164 /*
165 * Adjust ip_len to not reflect header,
166 * set ip_mff if more fragments are expected,
167 * convert offset of this to bytes.
168 */
169 ip->ip_len -= hlen;
170 if (ip->ip_off & IP_MF)
171 ip->ip_tos |= 1;
172 else
173 ip->ip_tos &= ~1;
174
175 ip->ip_off <<= 3;
176
177 /*
178 * If datagram marked as having more fragments
179 * or if this is not the first fragment,
180 * attempt reassembly; if it succeeds, proceed.
181 */
182 if (ip->ip_tos & 1 || ip->ip_off) {
183 ip = ip_reass(slirp, ip, fp);
184 if (ip == NULL)
185 return;
186 m = dtom(slirp, ip);
187 } else if (fp)
188 ip_freef(slirp, fp);
189
190 } else
191 ip->ip_len -= hlen;
192
193 /*
194 * Switch out to protocol's input routine.
195 */
196 switch (ip->ip_p) {
197 case IPPROTO_TCP:
198 tcp_input(m, hlen, (struct socket *)NULL, AF_INET);
199 break;
200 case IPPROTO_UDP:
201 udp_input(m, hlen);
202 break;
203 case IPPROTO_ICMP:
204 icmp_input(m, hlen);
205 break;
206 default:
207 m_free(m);
208 }
209 return;
210 bad:
211 m_free(m);
212 }
213
214 #define iptofrag(P) ((struct ipasfrag *)(((char *)(P)) - sizeof(struct qlink)))
215 #define fragtoip(P) ((struct ip *)(((char *)(P)) + sizeof(struct qlink)))
216 /*
217 * Take incoming datagram fragment and try to
218 * reassemble it into whole datagram. If a chain for
219 * reassembly of this datagram already exists, then it
220 * is given as fp; otherwise have to make a chain.
221 */
222 static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
223 {
224 register struct mbuf *m = dtom(slirp, ip);
225 register struct ipasfrag *q;
226 int hlen = ip->ip_hl << 2;
227 int i, next;
228
229 DEBUG_CALL("ip_reass");
230 DEBUG_ARG("ip = %p", ip);
231 DEBUG_ARG("fp = %p", fp);
232 DEBUG_ARG("m = %p", m);
233
234 /*
235 * Presence of header sizes in mbufs
236 * would confuse code below.
237 * Fragment m_data is concatenated.
238 */
239 m->m_data += hlen;
240 m->m_len -= hlen;
241
242 /*
243 * If first fragment to arrive, create a reassembly queue.
244 */
245 if (fp == NULL) {
246 struct mbuf *t = m_get(slirp);
247
248 if (t == NULL) {
249 goto dropfrag;
250 }
251 fp = mtod(t, struct ipq *);
252 insque(&fp->ip_link, &slirp->ipq.ip_link);
253 fp->ipq_ttl = IPFRAGTTL;
254 fp->ipq_p = ip->ip_p;
255 fp->ipq_id = ip->ip_id;
256 fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
257 fp->ipq_src = ip->ip_src;
258 fp->ipq_dst = ip->ip_dst;
259 q = (struct ipasfrag *)fp;
260 goto insert;
261 }
262
263 /*
264 * Find a segment which begins after this one does.
265 */
266 for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
267 q = q->ipf_next)
268 if (q->ipf_off > ip->ip_off)
269 break;
270
271 /*
272 * If there is a preceding segment, it may provide some of
273 * our data already. If so, drop the data from the incoming
274 * segment. If it provides all of our data, drop us.
275 */
276 if (q->ipf_prev != &fp->frag_link) {
277 struct ipasfrag *pq = q->ipf_prev;
278 i = pq->ipf_off + pq->ipf_len - ip->ip_off;
279 if (i > 0) {
280 if (i >= ip->ip_len)
281 goto dropfrag;
282 m_adj(dtom(slirp, ip), i);
283 ip->ip_off += i;
284 ip->ip_len -= i;
285 }
286 }
287
288 /*
289 * While we overlap succeeding segments trim them or,
290 * if they are completely covered, dequeue them.
291 */
292 while (q != (struct ipasfrag *)&fp->frag_link &&
293 ip->ip_off + ip->ip_len > q->ipf_off) {
294 i = (ip->ip_off + ip->ip_len) - q->ipf_off;
295 if (i < q->ipf_len) {
296 q->ipf_len -= i;
297 q->ipf_off += i;
298 m_adj(dtom(slirp, q), i);
299 break;
300 }
301 q = q->ipf_next;
302 m_free(dtom(slirp, q->ipf_prev));
303 ip_deq(q->ipf_prev);
304 }
305
306 insert:
307 /*
308 * Stick new segment in its place;
309 * check for complete reassembly.
310 */
311 ip_enq(iptofrag(ip), q->ipf_prev);
312 next = 0;
313 for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
314 q = q->ipf_next) {
315 if (q->ipf_off != next)
316 return NULL;
317 next += q->ipf_len;
318 }
319 if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
320 return NULL;
321
322 /*
323 * Reassembly is complete; concatenate fragments.
324 */
325 q = fp->frag_link.next;
326 m = dtom(slirp, q);
327
328 int was_ext = m->m_flags & M_EXT;
329
330 q = (struct ipasfrag *)q->ipf_next;
331 while (q != (struct ipasfrag *)&fp->frag_link) {
332 struct mbuf *t = dtom(slirp, q);
333 q = (struct ipasfrag *)q->ipf_next;
334 m_cat(m, t);
335 }
336
337 /*
338 * Create header for new ip packet by
339 * modifying header of first packet;
340 * dequeue and discard fragment reassembly header.
341 * Make header visible.
342 */
343 q = fp->frag_link.next;
344
345 /*
346 * If the fragments concatenated to an mbuf that's bigger than the total
347 * size of the fragment and the mbuf was not already using an m_ext buffer,
348 * then an m_ext buffer was alloced. But fp->ipq_next points to the old
349 * buffer (in the mbuf), so we must point ip into the new buffer.
350 */
351 if (!was_ext && m->m_flags & M_EXT) {
352 int delta = (char *)q - m->m_dat;
353 q = (struct ipasfrag *)(m->m_ext + delta);
354 }
355
356 ip = fragtoip(q);
357 ip->ip_len = next;
358 ip->ip_tos &= ~1;
359 ip->ip_src = fp->ipq_src;
360 ip->ip_dst = fp->ipq_dst;
361 remque(&fp->ip_link);
362 (void)m_free(dtom(slirp, fp));
363 m->m_len += (ip->ip_hl << 2);
364 m->m_data -= (ip->ip_hl << 2);
365
366 return ip;
367
368 dropfrag:
369 m_free(m);
370 return NULL;
371 }
372
373 /*
374 * Free a fragment reassembly header and all
375 * associated datagrams.
376 */
377 static void ip_freef(Slirp *slirp, struct ipq *fp)
378 {
379 register struct ipasfrag *q, *p;
380
381 for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
382 q = p) {
383 p = q->ipf_next;
384 ip_deq(q);
385 m_free(dtom(slirp, q));
386 }
387 remque(&fp->ip_link);
388 (void)m_free(dtom(slirp, fp));
389 }
390
391 /*
392 * Put an ip fragment on a reassembly chain.
393 * Like insque, but pointers in middle of structure.
394 */
395 static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
396 {
397 DEBUG_CALL("ip_enq");
398 DEBUG_ARG("prev = %p", prev);
399 p->ipf_prev = prev;
400 p->ipf_next = prev->ipf_next;
401 ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
402 prev->ipf_next = p;
403 }
404
405 /*
406 * To ip_enq as remque is to insque.
407 */
408 static void ip_deq(register struct ipasfrag *p)
409 {
410 ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
411 ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
412 }
413
414 /*
415 * IP timer processing;
416 * if a timer expires on a reassembly
417 * queue, discard it.
418 */
419 void ip_slowtimo(Slirp *slirp)
420 {
421 struct qlink *l;
422
423 DEBUG_CALL("ip_slowtimo");
424
425 l = slirp->ipq.ip_link.next;
426
427 if (l == NULL)
428 return;
429
430 while (l != &slirp->ipq.ip_link) {
431 struct ipq *fp = container_of(l, struct ipq, ip_link);
432 l = l->next;
433 if (--fp->ipq_ttl == 0) {
434 ip_freef(slirp, fp);
435 }
436 }
437 }
438
439 /*
440 * Strip out IP options, at higher
441 * level protocol in the kernel.
442 * Second argument is buffer to which options
443 * will be moved, and return value is their length.
444 * (XXX) should be deleted; last arg currently ignored.
445 */
446 void ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
447 {
448 register int i;
449 struct ip *ip = mtod(m, struct ip *);
450 register char *opts;
451 int olen;
452
453 olen = (ip->ip_hl << 2) - sizeof(struct ip);
454 opts = (char *)(ip + 1);
455 i = m->m_len - (sizeof(struct ip) + olen);
456 memcpy(opts, opts + olen, (unsigned)i);
457 m->m_len -= olen;
458
459 ip->ip_hl = sizeof(struct ip) >> 2;
460 }
+0
-169
vendor/libslirp/src/ip_output.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
30 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP are
35 * Copyright (c) 1995 Danny Gasparovski.
36 */
37
38 #include "slirp.h"
39
40 /* Number of packets queued before we start sending
41 * (to prevent allocing too many mbufs) */
42 #define IF_THRESH 10
43
44 /*
45 * IP output. The packet in mbuf chain m contains a skeletal IP
46 * header (with len, off, ttl, proto, tos, src, dst).
47 * The mbuf chain containing the packet will be freed.
48 * The mbuf opt, if present, will not be freed.
49 */
50 int ip_output(struct socket *so, struct mbuf *m0)
51 {
52 Slirp *slirp = m0->slirp;
53 register struct ip *ip;
54 register struct mbuf *m = m0;
55 register int hlen = sizeof(struct ip);
56 int len, off, error = 0;
57
58 DEBUG_CALL("ip_output");
59 DEBUG_ARG("so = %p", so);
60 DEBUG_ARG("m0 = %p", m0);
61
62 ip = mtod(m, struct ip *);
63 /*
64 * Fill in IP header.
65 */
66 ip->ip_v = IPVERSION;
67 ip->ip_off &= IP_DF;
68 ip->ip_id = htons(slirp->ip_id++);
69 ip->ip_hl = hlen >> 2;
70
71 /*
72 * If small enough for interface, can just send directly.
73 */
74 if ((uint16_t)ip->ip_len <= slirp->if_mtu) {
75 ip->ip_len = htons((uint16_t)ip->ip_len);
76 ip->ip_off = htons((uint16_t)ip->ip_off);
77 ip->ip_sum = 0;
78 ip->ip_sum = cksum(m, hlen);
79
80 if_output(so, m);
81 goto done;
82 }
83
84 /*
85 * Too large for interface; fragment if possible.
86 * Must be able to put at least 8 bytes per fragment.
87 */
88 if (ip->ip_off & IP_DF) {
89 error = -1;
90 goto bad;
91 }
92
93 len = (slirp->if_mtu - hlen) & ~7; /* ip databytes per packet */
94 if (len < 8) {
95 error = -1;
96 goto bad;
97 }
98
99 {
100 int mhlen, firstlen = len;
101 struct mbuf **mnext = &m->m_nextpkt;
102
103 /*
104 * Loop through length of segment after first fragment,
105 * make new header and copy data of each part and link onto chain.
106 */
107 m0 = m;
108 mhlen = sizeof(struct ip);
109 for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) {
110 register struct ip *mhip;
111 m = m_get(slirp);
112 if (m == NULL) {
113 error = -1;
114 goto sendorfree;
115 }
116 m->m_data += IF_MAXLINKHDR;
117 mhip = mtod(m, struct ip *);
118 *mhip = *ip;
119
120 m->m_len = mhlen;
121 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
122 if (ip->ip_off & IP_MF)
123 mhip->ip_off |= IP_MF;
124 if (off + len >= (uint16_t)ip->ip_len)
125 len = (uint16_t)ip->ip_len - off;
126 else
127 mhip->ip_off |= IP_MF;
128 mhip->ip_len = htons((uint16_t)(len + mhlen));
129
130 if (m_copy(m, m0, off, len) < 0) {
131 error = -1;
132 goto sendorfree;
133 }
134
135 mhip->ip_off = htons((uint16_t)mhip->ip_off);
136 mhip->ip_sum = 0;
137 mhip->ip_sum = cksum(m, mhlen);
138 *mnext = m;
139 mnext = &m->m_nextpkt;
140 }
141 /*
142 * Update first fragment by trimming what's been copied out
143 * and updating header, then send each fragment (in order).
144 */
145 m = m0;
146 m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len);
147 ip->ip_len = htons((uint16_t)m->m_len);
148 ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF));
149 ip->ip_sum = 0;
150 ip->ip_sum = cksum(m, hlen);
151 sendorfree:
152 for (m = m0; m; m = m0) {
153 m0 = m->m_nextpkt;
154 m->m_nextpkt = NULL;
155 if (error == 0)
156 if_output(so, m);
157 else
158 m_free(m);
159 }
160 }
161
162 done:
163 return (error);
164
165 bad:
166 m_free(m0);
167 goto done;
168 }
+0
-23
vendor/libslirp/src/libslirp-version.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 #ifndef LIBSLIRP_VERSION_H_
2 #define LIBSLIRP_VERSION_H_
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8 #define SLIRP_MAJOR_VERSION 4
9 #define SLIRP_MINOR_VERSION 0
10 #define SLIRP_MICRO_VERSION 0
11
12 #define SLIRP_CHECK_VERSION(major,minor,micro) \
13 (SLIRP_MAJOR_VERSION > (major) || \
14 (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \
15 (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \
16 SLIRP_MICRO_VERSION >= (micro)))
17
18 #ifdef __cplusplus
19 } /* extern "C" */
20 #endif
21
22 #endif /* LIBSLIRP_VERSION_H_ */
+0
-164
vendor/libslirp/src/libslirp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 #ifndef LIBSLIRP_H
2 #define LIBSLIRP_H
3
4 #include <stdint.h>
5 #include <stdbool.h>
6 #include <sys/types.h>
7
8 #ifdef _WIN32
9 #include <winsock2.h>
10 #include <in6addr.h>
11 #else
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #endif
15
16 #include "libslirp-version.h"
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21
22 typedef struct Slirp Slirp;
23
24 enum {
25 SLIRP_POLL_IN = 1 << 0,
26 SLIRP_POLL_OUT = 1 << 1,
27 SLIRP_POLL_PRI = 1 << 2,
28 SLIRP_POLL_ERR = 1 << 3,
29 SLIRP_POLL_HUP = 1 << 4,
30 };
31
32 typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque);
33 typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque);
34 typedef void (*SlirpTimerCb)(void *opaque);
35 typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque);
36 typedef int (*SlirpGetREventsCb)(int idx, void *opaque);
37
38 /*
39 * Callbacks from slirp
40 */
41 typedef struct SlirpCb {
42 /*
43 * Send an ethernet frame to the guest network. The opaque
44 * parameter is the one given to slirp_init(). The function
45 * doesn't need to send all the data and may return <len (no
46 * buffering is done on libslirp side, so the data will be dropped
47 * in this case). <0 reports an IO error.
48 */
49 SlirpWriteCb send_packet;
50 /* Print a message for an error due to guest misbehavior. */
51 void (*guest_error)(const char *msg, void *opaque);
52 /* Return the virtual clock value in nanoseconds */
53 int64_t (*clock_get_ns)(void *opaque);
54 /* Create a new timer with the given callback and opaque data */
55 void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
56 /* Remove and free a timer */
57 void (*timer_free)(void *timer, void *opaque);
58 /* Modify a timer to expire at @expire_time */
59 void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
60 /* Register a fd for future polling */
61 void (*register_poll_fd)(int fd, void *opaque);
62 /* Unregister a fd */
63 void (*unregister_poll_fd)(int fd, void *opaque);
64 /* Kick the io-thread, to signal that new events may be processed */
65 void (*notify)(void *opaque);
66 } SlirpCb;
67
68 #define SLIRP_CONFIG_VERSION_MIN 1
69 #define SLIRP_CONFIG_VERSION_MAX 1
70
71 typedef struct SlirpConfig {
72 /* Version must be provided */
73 uint32_t version;
74 /*
75 * Fields introduced in SlirpConfig version 1 begin
76 */
77 int restricted;
78 bool in_enabled;
79 struct in_addr vnetwork;
80 struct in_addr vnetmask;
81 struct in_addr vhost;
82 bool in6_enabled;
83 struct in6_addr vprefix_addr6;
84 uint8_t vprefix_len;
85 struct in6_addr vhost6;
86 const char *vhostname;
87 const char *tftp_server_name;
88 const char *tftp_path;
89 const char *bootfile;
90 struct in_addr vdhcp_start;
91 struct in_addr vnameserver;
92 struct in6_addr vnameserver6;
93 const char **vdnssearch;
94 const char *vdomainname;
95 /* Default: IF_MTU_DEFAULT */
96 size_t if_mtu;
97 /* Default: IF_MRU_DEFAULT */
98 size_t if_mru;
99 /* Prohibit connecting to 127.0.0.1:* */
100 bool disable_host_loopback;
101 /*
102 * Enable emulation code (*warning*: this code isn't safe, it is not
103 * recommended to enable it)
104 */
105 bool enable_emu;
106 /*
107 * Fields introduced in SlirpConfig version 2 begin
108 */
109 } SlirpConfig;
110
111 Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks,
112 void *opaque);
113 /* slirp_init is deprecated in favor of slirp_new */
114 Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
115 struct in_addr vnetmask, struct in_addr vhost,
116 bool in6_enabled, struct in6_addr vprefix_addr6,
117 uint8_t vprefix_len, struct in6_addr vhost6,
118 const char *vhostname, const char *tftp_server_name,
119 const char *tftp_path, const char *bootfile,
120 struct in_addr vdhcp_start, struct in_addr vnameserver,
121 struct in6_addr vnameserver6, const char **vdnssearch,
122 const char *vdomainname, const SlirpCb *callbacks,
123 void *opaque);
124 void slirp_cleanup(Slirp *slirp);
125
126 void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
127 SlirpAddPollCb add_poll, void *opaque);
128
129 void slirp_pollfds_poll(Slirp *slirp, int select_error,
130 SlirpGetREventsCb get_revents, void *opaque);
131
132 void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
133
134 int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
135 int host_port, struct in_addr guest_addr, int guest_port);
136 int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
137 int host_port);
138 int slirp_add_exec(Slirp *slirp, const char *cmdline,
139 struct in_addr *guest_addr, int guest_port);
140 int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
141 struct in_addr *guest_addr, int guest_port);
142
143 char *slirp_connection_info(Slirp *slirp);
144
145 void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
146 const uint8_t *buf, int size);
147 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
148 int guest_port);
149
150 void slirp_state_save(Slirp *s, SlirpWriteCb write_cb, void *opaque);
151
152 int slirp_state_load(Slirp *s, int version_id, SlirpReadCb read_cb,
153 void *opaque);
154
155 int slirp_state_version(void);
156
157 const char *slirp_version_string(void);
158
159 #ifdef __cplusplus
160 } /* extern "C" */
161 #endif
162
163 #endif /* LIBSLIRP_H */
+0
-16
vendor/libslirp/src/main.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #ifndef SLIRP_MAIN_H
6 #define SLIRP_MAIN_H
7
8 extern unsigned curtime;
9 extern struct in_addr loopback_addr;
10 extern unsigned long loopback_mask;
11
12 int if_encap(Slirp *slirp, struct mbuf *ifm);
13 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
14
15 #endif
+0
-224
vendor/libslirp/src/mbuf.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski
3 */
4
5 /*
6 * mbuf's in SLiRP are much simpler than the real mbufs in
7 * FreeBSD. They are fixed size, determined by the MTU,
8 * so that one whole packet can fit. Mbuf's cannot be
9 * chained together. If there's more data than the mbuf
10 * could hold, an external g_malloced buffer is pointed to
11 * by m_ext (and the data pointers) and M_EXT is set in
12 * the flags
13 */
14
15 #include "slirp.h"
16
17 #define MBUF_THRESH 30
18
19 /*
20 * Find a nice value for msize
21 */
22 #define SLIRP_MSIZE(mtu) \
23 (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + (mtu))
24
25 void m_init(Slirp *slirp)
26 {
27 slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist;
28 slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist;
29 }
30
31 void m_cleanup(Slirp *slirp)
32 {
33 struct mbuf *m, *next;
34
35 m = (struct mbuf *)slirp->m_usedlist.qh_link;
36 while ((struct quehead *)m != &slirp->m_usedlist) {
37 next = m->m_next;
38 if (m->m_flags & M_EXT) {
39 g_free(m->m_ext);
40 }
41 g_free(m);
42 m = next;
43 }
44 m = (struct mbuf *)slirp->m_freelist.qh_link;
45 while ((struct quehead *)m != &slirp->m_freelist) {
46 next = m->m_next;
47 g_free(m);
48 m = next;
49 }
50 }
51
52 /*
53 * Get an mbuf from the free list, if there are none
54 * allocate one
55 *
56 * Because fragmentation can occur if we alloc new mbufs and
57 * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
58 * which tells m_free to actually g_free() it
59 */
60 struct mbuf *m_get(Slirp *slirp)
61 {
62 register struct mbuf *m;
63 int flags = 0;
64
65 DEBUG_CALL("m_get");
66
67 if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
68 m = g_malloc(SLIRP_MSIZE(slirp->if_mtu));
69 slirp->mbuf_alloced++;
70 if (slirp->mbuf_alloced > MBUF_THRESH)
71 flags = M_DOFREE;
72 m->slirp = slirp;
73 } else {
74 m = (struct mbuf *)slirp->m_freelist.qh_link;
75 remque(m);
76 }
77
78 /* Insert it in the used list */
79 insque(m, &slirp->m_usedlist);
80 m->m_flags = (flags | M_USEDLIST);
81
82 /* Initialise it */
83 m->m_size = SLIRP_MSIZE(slirp->if_mtu) - offsetof(struct mbuf, m_dat);
84 m->m_data = m->m_dat;
85 m->m_len = 0;
86 m->m_nextpkt = NULL;
87 m->m_prevpkt = NULL;
88 m->resolution_requested = false;
89 m->expiration_date = (uint64_t)-1;
90 DEBUG_ARG("m = %p", m);
91 return m;
92 }
93
94 void m_free(struct mbuf *m)
95 {
96 DEBUG_CALL("m_free");
97 DEBUG_ARG("m = %p", m);
98
99 if (m) {
100 /* Remove from m_usedlist */
101 if (m->m_flags & M_USEDLIST)
102 remque(m);
103
104 /* If it's M_EXT, free() it */
105 if (m->m_flags & M_EXT) {
106 g_free(m->m_ext);
107 }
108 /*
109 * Either free() it or put it on the free list
110 */
111 if (m->m_flags & M_DOFREE) {
112 m->slirp->mbuf_alloced--;
113 g_free(m);
114 } else if ((m->m_flags & M_FREELIST) == 0) {
115 insque(m, &m->slirp->m_freelist);
116 m->m_flags = M_FREELIST; /* Clobber other flags */
117 }
118 } /* if(m) */
119 }
120
121 /*
122 * Copy data from one mbuf to the end of
123 * the other.. if result is too big for one mbuf, allocate
124 * an M_EXT data segment
125 */
126 void m_cat(struct mbuf *m, struct mbuf *n)
127 {
128 /*
129 * If there's no room, realloc
130 */
131 if (M_FREEROOM(m) < n->m_len)
132 m_inc(m, m->m_len + n->m_len);
133
134 memcpy(m->m_data + m->m_len, n->m_data, n->m_len);
135 m->m_len += n->m_len;
136
137 m_free(n);
138 }
139
140
141 /* make m 'size' bytes large from m_data */
142 void m_inc(struct mbuf *m, int size)
143 {
144 int gapsize;
145
146 /* some compilers throw up on gotos. This one we can fake. */
147 if (M_ROOM(m) > size) {
148 return;
149 }
150
151 if (m->m_flags & M_EXT) {
152 gapsize = m->m_data - m->m_ext;
153 m->m_ext = g_realloc(m->m_ext, size + gapsize);
154 } else {
155 gapsize = m->m_data - m->m_dat;
156 m->m_ext = g_malloc(size + gapsize);
157 memcpy(m->m_ext, m->m_dat, m->m_size);
158 m->m_flags |= M_EXT;
159 }
160
161 m->m_data = m->m_ext + gapsize;
162 m->m_size = size + gapsize;
163 }
164
165
166 void m_adj(struct mbuf *m, int len)
167 {
168 if (m == NULL)
169 return;
170 if (len >= 0) {
171 /* Trim from head */
172 m->m_data += len;
173 m->m_len -= len;
174 } else {
175 /* Trim from tail */
176 len = -len;
177 m->m_len -= len;
178 }
179 }
180
181
182 /*
183 * Copy len bytes from m, starting off bytes into n
184 */
185 int m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
186 {
187 if (len > M_FREEROOM(n))
188 return -1;
189
190 memcpy((n->m_data + n->m_len), (m->m_data + off), len);
191 n->m_len += len;
192 return 0;
193 }
194
195
196 /*
197 * Given a pointer into an mbuf, return the mbuf
198 * XXX This is a kludge, I should eliminate the need for it
199 * Fortunately, it's not used often
200 */
201 struct mbuf *dtom(Slirp *slirp, void *dat)
202 {
203 struct mbuf *m;
204
205 DEBUG_CALL("dtom");
206 DEBUG_ARG("dat = %p", dat);
207
208 /* bug corrected for M_EXT buffers */
209 for (m = (struct mbuf *)slirp->m_usedlist.qh_link;
210 (struct quehead *)m != &slirp->m_usedlist; m = m->m_next) {
211 if (m->m_flags & M_EXT) {
212 if ((char *)dat >= m->m_ext && (char *)dat < (m->m_ext + m->m_size))
213 return m;
214 } else {
215 if ((char *)dat >= m->m_dat && (char *)dat < (m->m_dat + m->m_size))
216 return m;
217 }
218 }
219
220 DEBUG_ERROR("dtom failed");
221
222 return (struct mbuf *)0;
223 }
+0
-127
vendor/libslirp/src/mbuf.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)mbuf.h 8.3 (Berkeley) 1/21/94
30 * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
31 */
32
33 #ifndef MBUF_H
34 #define MBUF_H
35
36 /*
37 * Macros for type conversion
38 * mtod(m,t) - convert mbuf pointer to data pointer of correct type
39 */
40 #define mtod(m, t) ((t)(m)->m_data)
41
42 /* XXX About mbufs for slirp:
43 * Only one mbuf is ever used in a chain, for each "cell" of data.
44 * m_nextpkt points to the next packet, if fragmented.
45 * If the data is too large, the M_EXT is used, and a larger block
46 * is alloced. Therefore, m_free[m] must check for M_EXT and if set
47 * free the m_ext. This is inefficient memory-wise, but who cares.
48 */
49
50 /*
51 * mbufs allow to have a gap between the start of the allocated buffer (m_ext if
52 * M_EXT is set, m_dat otherwise) and the in-use data:
53 *
54 * |--gapsize----->|---m_len------->
55 * |----------m_size------------------------------>
56 * |----M_ROOM-------------------->
57 * |-M_FREEROOM-->
58 *
59 * ^ ^ ^
60 * m_dat/m_ext m_data end of buffer
61 */
62
63 /*
64 * How much room is in the mbuf, from m_data to the end of the mbuf
65 */
66 #define M_ROOM(m) \
67 ((m->m_flags & M_EXT) ? (((m)->m_ext + (m)->m_size) - (m)->m_data) : \
68 (((m)->m_dat + (m)->m_size) - (m)->m_data))
69
70 /*
71 * How much free room there is
72 */
73 #define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
74
75 struct mbuf {
76 /* XXX should union some of these! */
77 /* header at beginning of each mbuf: */
78 struct mbuf *m_next; /* Linked list of mbufs */
79 struct mbuf *m_prev;
80 struct mbuf *m_nextpkt; /* Next packet in queue/record */
81 struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */
82 int m_flags; /* Misc flags */
83
84 int m_size; /* Size of mbuf, from m_dat or m_ext */
85 struct socket *m_so;
86
87 char *m_data; /* Current location of data */
88 int m_len; /* Amount of data in this mbuf, from m_data */
89
90 Slirp *slirp;
91 bool resolution_requested;
92 uint64_t expiration_date;
93 char *m_ext;
94 /* start of dynamic buffer area, must be last element */
95 char m_dat[];
96 };
97
98 #define ifq_prev m_prev
99 #define ifq_next m_next
100 #define ifs_prev m_prevpkt
101 #define ifs_next m_nextpkt
102 #define ifq_so m_so
103
104 #define M_EXT 0x01 /* m_ext points to more (malloced) data */
105 #define M_FREELIST 0x02 /* mbuf is on free list */
106 #define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */
107 #define M_DOFREE \
108 0x08 /* when m_free is called on the mbuf, free() \
109 * it rather than putting it on the free list */
110
111 void m_init(Slirp *);
112 void m_cleanup(Slirp *slirp);
113 struct mbuf *m_get(Slirp *);
114 void m_free(struct mbuf *);
115 void m_cat(register struct mbuf *, register struct mbuf *);
116 void m_inc(struct mbuf *, int);
117 void m_adj(struct mbuf *, int);
118 int m_copy(struct mbuf *, struct mbuf *, int, int);
119 struct mbuf *dtom(Slirp *, void *);
120
121 static inline void ifs_init(struct mbuf *ifm)
122 {
123 ifm->ifs_next = ifm->ifs_prev = ifm;
124 }
125
126 #endif
+0
-298
vendor/libslirp/src/misc.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #include "slirp.h"
6
7 inline void insque(void *a, void *b)
8 {
9 register struct quehead *element = (struct quehead *)a;
10 register struct quehead *head = (struct quehead *)b;
11 element->qh_link = head->qh_link;
12 head->qh_link = (struct quehead *)element;
13 element->qh_rlink = (struct quehead *)head;
14 ((struct quehead *)(element->qh_link))->qh_rlink =
15 (struct quehead *)element;
16 }
17
18 inline void remque(void *a)
19 {
20 register struct quehead *element = (struct quehead *)a;
21 ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
22 ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
23 element->qh_rlink = NULL;
24 }
25
26 /* TODO: IPv6 */
27 struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
28 void *opaque, struct in_addr addr, int port)
29 {
30 struct gfwd_list *f = g_new0(struct gfwd_list, 1);
31
32 f->write_cb = write_cb;
33 f->opaque = opaque;
34 f->ex_fport = port;
35 f->ex_addr = addr;
36 f->ex_next = *ex_ptr;
37 *ex_ptr = f;
38
39 return f;
40 }
41
42 struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
43 struct in_addr addr, int port)
44 {
45 struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
46
47 f->ex_exec = g_strdup(cmdline);
48
49 return f;
50 }
51
52 static int slirp_socketpair_with_oob(int sv[2])
53 {
54 struct sockaddr_in addr = {
55 .sin_family = AF_INET,
56 .sin_port = 0,
57 .sin_addr.s_addr = INADDR_ANY,
58 };
59 socklen_t addrlen = sizeof(addr);
60 int ret, s;
61
62 sv[1] = -1;
63 s = slirp_socket(AF_INET, SOCK_STREAM, 0);
64 if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
65 listen(s, 1) < 0 ||
66 getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
67 goto err;
68 }
69
70 sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);
71 if (sv[1] < 0) {
72 goto err;
73 }
74 /*
75 * This connect won't block because we've already listen()ed on
76 * the server end (even though we won't accept() the connection
77 * until later on).
78 */
79 do {
80 ret = connect(sv[1], (struct sockaddr *)&addr, addrlen);
81 } while (ret < 0 && errno == EINTR);
82 if (ret < 0) {
83 goto err;
84 }
85
86 do {
87 sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen);
88 } while (sv[0] < 0 && errno == EINTR);
89 if (sv[0] < 0) {
90 goto err;
91 }
92
93 closesocket(s);
94 return 0;
95
96 err:
97 g_critical("slirp_socketpair(): %s", strerror(errno));
98 if (s >= 0) {
99 closesocket(s);
100 }
101 if (sv[1] >= 0) {
102 closesocket(sv[1]);
103 }
104 return -1;
105 }
106
107 static void fork_exec_child_setup(gpointer data)
108 {
109 #ifndef _WIN32
110 setsid();
111 #endif
112 }
113
114 #pragma GCC diagnostic push
115 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
116
117 #if !GLIB_CHECK_VERSION(2, 58, 0)
118 typedef struct SlirpGSpawnFds {
119 GSpawnChildSetupFunc child_setup;
120 gpointer user_data;
121 gint stdin_fd;
122 gint stdout_fd;
123 gint stderr_fd;
124 } SlirpGSpawnFds;
125
126 static inline void slirp_gspawn_fds_setup(gpointer user_data)
127 {
128 SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;
129
130 dup2(q->stdin_fd, 0);
131 dup2(q->stdout_fd, 1);
132 dup2(q->stderr_fd, 2);
133 q->child_setup(q->user_data);
134 }
135 #endif
136
137 static inline gboolean
138 g_spawn_async_with_fds_slirp(const gchar *working_directory, gchar **argv,
139 gchar **envp, GSpawnFlags flags,
140 GSpawnChildSetupFunc child_setup,
141 gpointer user_data, GPid *child_pid, gint stdin_fd,
142 gint stdout_fd, gint stderr_fd, GError **error)
143 {
144 #if GLIB_CHECK_VERSION(2, 58, 0)
145 return g_spawn_async_with_fds(working_directory, argv, envp, flags,
146 child_setup, user_data, child_pid, stdin_fd,
147 stdout_fd, stderr_fd, error);
148 #else
149 SlirpGSpawnFds setup = {
150 .child_setup = child_setup,
151 .user_data = user_data,
152 .stdin_fd = stdin_fd,
153 .stdout_fd = stdout_fd,
154 .stderr_fd = stderr_fd,
155 };
156
157 return g_spawn_async(working_directory, argv, envp, flags,
158 slirp_gspawn_fds_setup, &setup, child_pid, error);
159 #endif
160 }
161
162 #define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
163 g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
164
165 #pragma GCC diagnostic pop
166
167 int fork_exec(struct socket *so, const char *ex)
168 {
169 GError *err = NULL;
170 char **argv;
171 int opt, sp[2];
172
173 DEBUG_CALL("fork_exec");
174 DEBUG_ARG("so = %p", so);
175 DEBUG_ARG("ex = %p", ex);
176
177 if (slirp_socketpair_with_oob(sp) < 0) {
178 return 0;
179 }
180
181 argv = g_strsplit(ex, " ", -1);
182 g_spawn_async_with_fds(NULL /* cwd */, argv, NULL /* env */,
183 G_SPAWN_SEARCH_PATH, fork_exec_child_setup,
184 NULL /* data */, NULL /* child_pid */, sp[1], sp[1],
185 sp[1], &err);
186 g_strfreev(argv);
187
188 if (err) {
189 g_critical("fork_exec: %s", err->message);
190 g_error_free(err);
191 closesocket(sp[0]);
192 closesocket(sp[1]);
193 return 0;
194 }
195
196 so->s = sp[0];
197 closesocket(sp[1]);
198 slirp_socket_set_fast_reuse(so->s);
199 opt = 1;
200 setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
201 slirp_set_nonblock(so->s);
202 so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
203 return 1;
204 }
205
206 char *slirp_connection_info(Slirp *slirp)
207 {
208 GString *str = g_string_new(NULL);
209 const char *const tcpstates[] = {
210 [TCPS_CLOSED] = "CLOSED", [TCPS_LISTEN] = "LISTEN",
211 [TCPS_SYN_SENT] = "SYN_SENT", [TCPS_SYN_RECEIVED] = "SYN_RCVD",
212 [TCPS_ESTABLISHED] = "ESTABLISHED", [TCPS_CLOSE_WAIT] = "CLOSE_WAIT",
213 [TCPS_FIN_WAIT_1] = "FIN_WAIT_1", [TCPS_CLOSING] = "CLOSING",
214 [TCPS_LAST_ACK] = "LAST_ACK", [TCPS_FIN_WAIT_2] = "FIN_WAIT_2",
215 [TCPS_TIME_WAIT] = "TIME_WAIT",
216 };
217 struct in_addr dst_addr;
218 struct sockaddr_in src;
219 socklen_t src_len;
220 uint16_t dst_port;
221 struct socket *so;
222 const char *state;
223 char buf[20];
224
225 g_string_append_printf(str,
226 " Protocol[State] FD Source Address Port "
227 "Dest. Address Port RecvQ SendQ\n");
228
229 /* TODO: IPv6 */
230
231 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
232 if (so->so_state & SS_HOSTFWD) {
233 state = "HOST_FORWARD";
234 } else if (so->so_tcpcb) {
235 state = tcpstates[so->so_tcpcb->t_state];
236 } else {
237 state = "NONE";
238 }
239 if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
240 src_len = sizeof(src);
241 getsockname(so->s, (struct sockaddr *)&src, &src_len);
242 dst_addr = so->so_laddr;
243 dst_port = so->so_lport;
244 } else {
245 src.sin_addr = so->so_laddr;
246 src.sin_port = so->so_lport;
247 dst_addr = so->so_faddr;
248 dst_port = so->so_fport;
249 }
250 snprintf(buf, sizeof(buf), " TCP[%s]", state);
251 g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
252 src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
253 "*",
254 ntohs(src.sin_port));
255 g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr),
256 ntohs(dst_port), so->so_rcv.sb_cc,
257 so->so_snd.sb_cc);
258 }
259
260 for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
261 if (so->so_state & SS_HOSTFWD) {
262 snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]");
263 src_len = sizeof(src);
264 getsockname(so->s, (struct sockaddr *)&src, &src_len);
265 dst_addr = so->so_laddr;
266 dst_port = so->so_lport;
267 } else {
268 snprintf(buf, sizeof(buf), " UDP[%d sec]",
269 (so->so_expire - curtime) / 1000);
270 src.sin_addr = so->so_laddr;
271 src.sin_port = so->so_lport;
272 dst_addr = so->so_faddr;
273 dst_port = so->so_fport;
274 }
275 g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
276 src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
277 "*",
278 ntohs(src.sin_port));
279 g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr),
280 ntohs(dst_port), so->so_rcv.sb_cc,
281 so->so_snd.sb_cc);
282 }
283
284 for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
285 snprintf(buf, sizeof(buf), " ICMP[%d sec]",
286 (so->so_expire - curtime) / 1000);
287 src.sin_addr = so->so_laddr;
288 dst_addr = so->so_faddr;
289 g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s,
290 src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
291 "*");
292 g_string_append_printf(str, "%15s - %5d %5d\n", inet_ntoa(dst_addr),
293 so->so_rcv.sb_cc, so->so_snd.sb_cc);
294 }
295
296 return g_string_free(str, FALSE);
297 }
+0
-63
vendor/libslirp/src/misc.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #ifndef MISC_H
6 #define MISC_H
7
8 #include "libslirp.h"
9
10 struct gfwd_list {
11 SlirpWriteCb write_cb;
12 void *opaque;
13 struct in_addr ex_addr; /* Server address */
14 int ex_fport; /* Port to telnet to */
15 char *ex_exec; /* Command line of what to exec */
16 struct gfwd_list *ex_next;
17 };
18
19 #define EMU_NONE 0x0
20
21 /* TCP emulations */
22 #define EMU_CTL 0x1
23 #define EMU_FTP 0x2
24 #define EMU_KSH 0x3
25 #define EMU_IRC 0x4
26 #define EMU_REALAUDIO 0x5
27 #define EMU_RLOGIN 0x6
28 #define EMU_IDENT 0x7
29
30 #define EMU_NOCONNECT 0x10 /* Don't connect */
31
32 struct tos_t {
33 uint16_t lport;
34 uint16_t fport;
35 uint8_t tos;
36 uint8_t emu;
37 };
38
39 struct emu_t {
40 uint16_t lport;
41 uint16_t fport;
42 uint8_t tos;
43 uint8_t emu;
44 struct emu_t *next;
45 };
46
47 struct slirp_quehead {
48 struct slirp_quehead *qh_link;
49 struct slirp_quehead *qh_rlink;
50 };
51
52 void slirp_insque(void *, void *);
53 void slirp_remque(void *);
54 int fork_exec(struct socket *so, const char *ex);
55
56 struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
57 void *opaque, struct in_addr addr, int port);
58
59 struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
60 struct in_addr addr, int port);
61
62 #endif
+0
-445
vendor/libslirp/src/ncsi-pkt.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright Gavin Shan, IBM Corporation 2016.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
32 * OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #ifndef NCSI_PKT_H
36 #define NCSI_PKT_H
37
38 /* from linux/net/ncsi/ncsi-pkt.h */
39 #define __be32 uint32_t
40 #define __be16 uint16_t
41
42 struct ncsi_pkt_hdr {
43 unsigned char mc_id; /* Management controller ID */
44 unsigned char revision; /* NCSI version - 0x01 */
45 unsigned char reserved; /* Reserved */
46 unsigned char id; /* Packet sequence number */
47 unsigned char type; /* Packet type */
48 unsigned char channel; /* Network controller ID */
49 __be16 length; /* Payload length */
50 __be32 reserved1[2]; /* Reserved */
51 };
52
53 struct ncsi_cmd_pkt_hdr {
54 struct ncsi_pkt_hdr common; /* Common NCSI packet header */
55 };
56
57 struct ncsi_rsp_pkt_hdr {
58 struct ncsi_pkt_hdr common; /* Common NCSI packet header */
59 __be16 code; /* Response code */
60 __be16 reason; /* Response reason */
61 };
62
63 struct ncsi_aen_pkt_hdr {
64 struct ncsi_pkt_hdr common; /* Common NCSI packet header */
65 unsigned char reserved2[3]; /* Reserved */
66 unsigned char type; /* AEN packet type */
67 };
68
69 /* NCSI common command packet */
70 struct ncsi_cmd_pkt {
71 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
72 __be32 checksum; /* Checksum */
73 unsigned char pad[26];
74 };
75
76 struct ncsi_rsp_pkt {
77 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
78 __be32 checksum; /* Checksum */
79 unsigned char pad[22];
80 };
81
82 /* Select Package */
83 struct ncsi_cmd_sp_pkt {
84 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
85 unsigned char reserved[3]; /* Reserved */
86 unsigned char hw_arbitration; /* HW arbitration */
87 __be32 checksum; /* Checksum */
88 unsigned char pad[22];
89 };
90
91 /* Disable Channel */
92 struct ncsi_cmd_dc_pkt {
93 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
94 unsigned char reserved[3]; /* Reserved */
95 unsigned char ald; /* Allow link down */
96 __be32 checksum; /* Checksum */
97 unsigned char pad[22];
98 };
99
100 /* Reset Channel */
101 struct ncsi_cmd_rc_pkt {
102 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
103 __be32 reserved; /* Reserved */
104 __be32 checksum; /* Checksum */
105 unsigned char pad[22];
106 };
107
108 /* AEN Enable */
109 struct ncsi_cmd_ae_pkt {
110 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
111 unsigned char reserved[3]; /* Reserved */
112 unsigned char mc_id; /* MC ID */
113 __be32 mode; /* AEN working mode */
114 __be32 checksum; /* Checksum */
115 unsigned char pad[18];
116 };
117
118 /* Set Link */
119 struct ncsi_cmd_sl_pkt {
120 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
121 __be32 mode; /* Link working mode */
122 __be32 oem_mode; /* OEM link mode */
123 __be32 checksum; /* Checksum */
124 unsigned char pad[18];
125 };
126
127 /* Set VLAN Filter */
128 struct ncsi_cmd_svf_pkt {
129 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
130 __be16 reserved; /* Reserved */
131 __be16 vlan; /* VLAN ID */
132 __be16 reserved1; /* Reserved */
133 unsigned char index; /* VLAN table index */
134 unsigned char enable; /* Enable or disable */
135 __be32 checksum; /* Checksum */
136 unsigned char pad[14];
137 };
138
139 /* Enable VLAN */
140 struct ncsi_cmd_ev_pkt {
141 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
142 unsigned char reserved[3]; /* Reserved */
143 unsigned char mode; /* VLAN filter mode */
144 __be32 checksum; /* Checksum */
145 unsigned char pad[22];
146 };
147
148 /* Set MAC Address */
149 struct ncsi_cmd_sma_pkt {
150 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
151 unsigned char mac[6]; /* MAC address */
152 unsigned char index; /* MAC table index */
153 unsigned char at_e; /* Addr type and operation */
154 __be32 checksum; /* Checksum */
155 unsigned char pad[18];
156 };
157
158 /* Enable Broadcast Filter */
159 struct ncsi_cmd_ebf_pkt {
160 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
161 __be32 mode; /* Filter mode */
162 __be32 checksum; /* Checksum */
163 unsigned char pad[22];
164 };
165
166 /* Enable Global Multicast Filter */
167 struct ncsi_cmd_egmf_pkt {
168 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
169 __be32 mode; /* Global MC mode */
170 __be32 checksum; /* Checksum */
171 unsigned char pad[22];
172 };
173
174 /* Set NCSI Flow Control */
175 struct ncsi_cmd_snfc_pkt {
176 struct ncsi_cmd_pkt_hdr cmd; /* Command header */
177 unsigned char reserved[3]; /* Reserved */
178 unsigned char mode; /* Flow control mode */
179 __be32 checksum; /* Checksum */
180 unsigned char pad[22];
181 };
182
183 /* Get Link Status */
184 struct ncsi_rsp_gls_pkt {
185 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
186 __be32 status; /* Link status */
187 __be32 other; /* Other indications */
188 __be32 oem_status; /* OEM link status */
189 __be32 checksum;
190 unsigned char pad[10];
191 };
192
193 /* Get Version ID */
194 struct ncsi_rsp_gvi_pkt {
195 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
196 __be32 ncsi_version; /* NCSI version */
197 unsigned char reserved[3]; /* Reserved */
198 unsigned char alpha2; /* NCSI version */
199 unsigned char fw_name[12]; /* f/w name string */
200 __be32 fw_version; /* f/w version */
201 __be16 pci_ids[4]; /* PCI IDs */
202 __be32 mf_id; /* Manufacture ID */
203 __be32 checksum;
204 };
205
206 /* Get Capabilities */
207 struct ncsi_rsp_gc_pkt {
208 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
209 __be32 cap; /* Capabilities */
210 __be32 bc_cap; /* Broadcast cap */
211 __be32 mc_cap; /* Multicast cap */
212 __be32 buf_cap; /* Buffering cap */
213 __be32 aen_cap; /* AEN cap */
214 unsigned char vlan_cnt; /* VLAN filter count */
215 unsigned char mixed_cnt; /* Mix filter count */
216 unsigned char mc_cnt; /* MC filter count */
217 unsigned char uc_cnt; /* UC filter count */
218 unsigned char reserved[2]; /* Reserved */
219 unsigned char vlan_mode; /* VLAN mode */
220 unsigned char channel_cnt; /* Channel count */
221 __be32 checksum; /* Checksum */
222 };
223
224 /* Get Parameters */
225 struct ncsi_rsp_gp_pkt {
226 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
227 unsigned char mac_cnt; /* Number of MAC addr */
228 unsigned char reserved[2]; /* Reserved */
229 unsigned char mac_enable; /* MAC addr enable flags */
230 unsigned char vlan_cnt; /* VLAN tag count */
231 unsigned char reserved1; /* Reserved */
232 __be16 vlan_enable; /* VLAN tag enable flags */
233 __be32 link_mode; /* Link setting */
234 __be32 bc_mode; /* BC filter mode */
235 __be32 valid_modes; /* Valid mode parameters */
236 unsigned char vlan_mode; /* VLAN mode */
237 unsigned char fc_mode; /* Flow control mode */
238 unsigned char reserved2[2]; /* Reserved */
239 __be32 aen_mode; /* AEN mode */
240 unsigned char mac[6]; /* Supported MAC addr */
241 __be16 vlan; /* Supported VLAN tags */
242 __be32 checksum; /* Checksum */
243 };
244
245 /* Get Controller Packet Statistics */
246 struct ncsi_rsp_gcps_pkt {
247 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
248 __be32 cnt_hi; /* Counter cleared */
249 __be32 cnt_lo; /* Counter cleared */
250 __be32 rx_bytes; /* Rx bytes */
251 __be32 tx_bytes; /* Tx bytes */
252 __be32 rx_uc_pkts; /* Rx UC packets */
253 __be32 rx_mc_pkts; /* Rx MC packets */
254 __be32 rx_bc_pkts; /* Rx BC packets */
255 __be32 tx_uc_pkts; /* Tx UC packets */
256 __be32 tx_mc_pkts; /* Tx MC packets */
257 __be32 tx_bc_pkts; /* Tx BC packets */
258 __be32 fcs_err; /* FCS errors */
259 __be32 align_err; /* Alignment errors */
260 __be32 false_carrier; /* False carrier detection */
261 __be32 runt_pkts; /* Rx runt packets */
262 __be32 jabber_pkts; /* Rx jabber packets */
263 __be32 rx_pause_xon; /* Rx pause XON frames */
264 __be32 rx_pause_xoff; /* Rx XOFF frames */
265 __be32 tx_pause_xon; /* Tx XON frames */
266 __be32 tx_pause_xoff; /* Tx XOFF frames */
267 __be32 tx_s_collision; /* Single collision frames */
268 __be32 tx_m_collision; /* Multiple collision frames */
269 __be32 l_collision; /* Late collision frames */
270 __be32 e_collision; /* Excessive collision frames */
271 __be32 rx_ctl_frames; /* Rx control frames */
272 __be32 rx_64_frames; /* Rx 64-bytes frames */
273 __be32 rx_127_frames; /* Rx 65-127 bytes frames */
274 __be32 rx_255_frames; /* Rx 128-255 bytes frames */
275 __be32 rx_511_frames; /* Rx 256-511 bytes frames */
276 __be32 rx_1023_frames; /* Rx 512-1023 bytes frames */
277 __be32 rx_1522_frames; /* Rx 1024-1522 bytes frames */
278 __be32 rx_9022_frames; /* Rx 1523-9022 bytes frames */
279 __be32 tx_64_frames; /* Tx 64-bytes frames */
280 __be32 tx_127_frames; /* Tx 65-127 bytes frames */
281 __be32 tx_255_frames; /* Tx 128-255 bytes frames */
282 __be32 tx_511_frames; /* Tx 256-511 bytes frames */
283 __be32 tx_1023_frames; /* Tx 512-1023 bytes frames */
284 __be32 tx_1522_frames; /* Tx 1024-1522 bytes frames */
285 __be32 tx_9022_frames; /* Tx 1523-9022 bytes frames */
286 __be32 rx_valid_bytes; /* Rx valid bytes */
287 __be32 rx_runt_pkts; /* Rx error runt packets */
288 __be32 rx_jabber_pkts; /* Rx error jabber packets */
289 __be32 checksum; /* Checksum */
290 };
291
292 /* Get NCSI Statistics */
293 struct ncsi_rsp_gns_pkt {
294 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
295 __be32 rx_cmds; /* Rx NCSI commands */
296 __be32 dropped_cmds; /* Dropped commands */
297 __be32 cmd_type_errs; /* Command type errors */
298 __be32 cmd_csum_errs; /* Command checksum errors */
299 __be32 rx_pkts; /* Rx NCSI packets */
300 __be32 tx_pkts; /* Tx NCSI packets */
301 __be32 tx_aen_pkts; /* Tx AEN packets */
302 __be32 checksum; /* Checksum */
303 };
304
305 /* Get NCSI Pass-through Statistics */
306 struct ncsi_rsp_gnpts_pkt {
307 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
308 __be32 tx_pkts; /* Tx packets */
309 __be32 tx_dropped; /* Tx dropped packets */
310 __be32 tx_channel_err; /* Tx channel errors */
311 __be32 tx_us_err; /* Tx undersize errors */
312 __be32 rx_pkts; /* Rx packets */
313 __be32 rx_dropped; /* Rx dropped packets */
314 __be32 rx_channel_err; /* Rx channel errors */
315 __be32 rx_us_err; /* Rx undersize errors */
316 __be32 rx_os_err; /* Rx oversize errors */
317 __be32 checksum; /* Checksum */
318 };
319
320 /* Get package status */
321 struct ncsi_rsp_gps_pkt {
322 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
323 __be32 status; /* Hardware arbitration status */
324 __be32 checksum;
325 };
326
327 /* Get package UUID */
328 struct ncsi_rsp_gpuuid_pkt {
329 struct ncsi_rsp_pkt_hdr rsp; /* Response header */
330 unsigned char uuid[16]; /* UUID */
331 __be32 checksum;
332 };
333
334 /* AEN: Link State Change */
335 struct ncsi_aen_lsc_pkt {
336 struct ncsi_aen_pkt_hdr aen; /* AEN header */
337 __be32 status; /* Link status */
338 __be32 oem_status; /* OEM link status */
339 __be32 checksum; /* Checksum */
340 unsigned char pad[14];
341 };
342
343 /* AEN: Configuration Required */
344 struct ncsi_aen_cr_pkt {
345 struct ncsi_aen_pkt_hdr aen; /* AEN header */
346 __be32 checksum; /* Checksum */
347 unsigned char pad[22];
348 };
349
350 /* AEN: Host Network Controller Driver Status Change */
351 struct ncsi_aen_hncdsc_pkt {
352 struct ncsi_aen_pkt_hdr aen; /* AEN header */
353 __be32 status; /* Status */
354 __be32 checksum; /* Checksum */
355 unsigned char pad[18];
356 };
357
358 /* NCSI packet revision */
359 #define NCSI_PKT_REVISION 0x01
360
361 /* NCSI packet commands */
362 #define NCSI_PKT_CMD_CIS 0x00 /* Clear Initial State */
363 #define NCSI_PKT_CMD_SP 0x01 /* Select Package */
364 #define NCSI_PKT_CMD_DP 0x02 /* Deselect Package */
365 #define NCSI_PKT_CMD_EC 0x03 /* Enable Channel */
366 #define NCSI_PKT_CMD_DC 0x04 /* Disable Channel */
367 #define NCSI_PKT_CMD_RC 0x05 /* Reset Channel */
368 #define NCSI_PKT_CMD_ECNT 0x06 /* Enable Channel Network Tx */
369 #define NCSI_PKT_CMD_DCNT 0x07 /* Disable Channel Network Tx */
370 #define NCSI_PKT_CMD_AE 0x08 /* AEN Enable */
371 #define NCSI_PKT_CMD_SL 0x09 /* Set Link */
372 #define NCSI_PKT_CMD_GLS 0x0a /* Get Link */
373 #define NCSI_PKT_CMD_SVF 0x0b /* Set VLAN Filter */
374 #define NCSI_PKT_CMD_EV 0x0c /* Enable VLAN */
375 #define NCSI_PKT_CMD_DV 0x0d /* Disable VLAN */
376 #define NCSI_PKT_CMD_SMA 0x0e /* Set MAC address */
377 #define NCSI_PKT_CMD_EBF 0x10 /* Enable Broadcast Filter */
378 #define NCSI_PKT_CMD_DBF 0x11 /* Disable Broadcast Filter */
379 #define NCSI_PKT_CMD_EGMF 0x12 /* Enable Global Multicast Filter */
380 #define NCSI_PKT_CMD_DGMF 0x13 /* Disable Global Multicast Filter */
381 #define NCSI_PKT_CMD_SNFC 0x14 /* Set NCSI Flow Control */
382 #define NCSI_PKT_CMD_GVI 0x15 /* Get Version ID */
383 #define NCSI_PKT_CMD_GC 0x16 /* Get Capabilities */
384 #define NCSI_PKT_CMD_GP 0x17 /* Get Parameters */
385 #define NCSI_PKT_CMD_GCPS 0x18 /* Get Controller Packet Statistics */
386 #define NCSI_PKT_CMD_GNS 0x19 /* Get NCSI Statistics */
387 #define NCSI_PKT_CMD_GNPTS 0x1a /* Get NCSI Pass-throu Statistics */
388 #define NCSI_PKT_CMD_GPS 0x1b /* Get package status */
389 #define NCSI_PKT_CMD_OEM 0x50 /* OEM */
390 #define NCSI_PKT_CMD_PLDM 0x51 /* PLDM request over NCSI over RBT */
391 #define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */
392
393 /* NCSI packet responses */
394 #define NCSI_PKT_RSP_CIS (NCSI_PKT_CMD_CIS + 0x80)
395 #define NCSI_PKT_RSP_SP (NCSI_PKT_CMD_SP + 0x80)
396 #define NCSI_PKT_RSP_DP (NCSI_PKT_CMD_DP + 0x80)
397 #define NCSI_PKT_RSP_EC (NCSI_PKT_CMD_EC + 0x80)
398 #define NCSI_PKT_RSP_DC (NCSI_PKT_CMD_DC + 0x80)
399 #define NCSI_PKT_RSP_RC (NCSI_PKT_CMD_RC + 0x80)
400 #define NCSI_PKT_RSP_ECNT (NCSI_PKT_CMD_ECNT + 0x80)
401 #define NCSI_PKT_RSP_DCNT (NCSI_PKT_CMD_DCNT + 0x80)
402 #define NCSI_PKT_RSP_AE (NCSI_PKT_CMD_AE + 0x80)
403 #define NCSI_PKT_RSP_SL (NCSI_PKT_CMD_SL + 0x80)
404 #define NCSI_PKT_RSP_GLS (NCSI_PKT_CMD_GLS + 0x80)
405 #define NCSI_PKT_RSP_SVF (NCSI_PKT_CMD_SVF + 0x80)
406 #define NCSI_PKT_RSP_EV (NCSI_PKT_CMD_EV + 0x80)
407 #define NCSI_PKT_RSP_DV (NCSI_PKT_CMD_DV + 0x80)
408 #define NCSI_PKT_RSP_SMA (NCSI_PKT_CMD_SMA + 0x80)
409 #define NCSI_PKT_RSP_EBF (NCSI_PKT_CMD_EBF + 0x80)
410 #define NCSI_PKT_RSP_DBF (NCSI_PKT_CMD_DBF + 0x80)
411 #define NCSI_PKT_RSP_EGMF (NCSI_PKT_CMD_EGMF + 0x80)
412 #define NCSI_PKT_RSP_DGMF (NCSI_PKT_CMD_DGMF + 0x80)
413 #define NCSI_PKT_RSP_SNFC (NCSI_PKT_CMD_SNFC + 0x80)
414 #define NCSI_PKT_RSP_GVI (NCSI_PKT_CMD_GVI + 0x80)
415 #define NCSI_PKT_RSP_GC (NCSI_PKT_CMD_GC + 0x80)
416 #define NCSI_PKT_RSP_GP (NCSI_PKT_CMD_GP + 0x80)
417 #define NCSI_PKT_RSP_GCPS (NCSI_PKT_CMD_GCPS + 0x80)
418 #define NCSI_PKT_RSP_GNS (NCSI_PKT_CMD_GNS + 0x80)
419 #define NCSI_PKT_RSP_GNPTS (NCSI_PKT_CMD_GNPTS + 0x80)
420 #define NCSI_PKT_RSP_GPS (NCSI_PKT_CMD_GPS + 0x80)
421 #define NCSI_PKT_RSP_OEM (NCSI_PKT_CMD_OEM + 0x80)
422 #define NCSI_PKT_RSP_PLDM (NCSI_PKT_CMD_PLDM + 0x80)
423 #define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80)
424
425 /* NCSI response code/reason */
426 #define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */
427 #define NCSI_PKT_RSP_C_FAILED 0x0001 /* Command Failed */
428 #define NCSI_PKT_RSP_C_UNAVAILABLE 0x0002 /* Command Unavailable */
429 #define NCSI_PKT_RSP_C_UNSUPPORTED 0x0003 /* Command Unsupported */
430 #define NCSI_PKT_RSP_R_NO_ERROR 0x0000 /* No Error */
431 #define NCSI_PKT_RSP_R_INTERFACE 0x0001 /* Interface not ready */
432 #define NCSI_PKT_RSP_R_PARAM 0x0002 /* Invalid Parameter */
433 #define NCSI_PKT_RSP_R_CHANNEL 0x0003 /* Channel not Ready */
434 #define NCSI_PKT_RSP_R_PACKAGE 0x0004 /* Package not Ready */
435 #define NCSI_PKT_RSP_R_LENGTH 0x0005 /* Invalid payload length */
436 #define NCSI_PKT_RSP_R_UNKNOWN 0x7fff /* Command type unsupported */
437
438 /* NCSI AEN packet type */
439 #define NCSI_PKT_AEN 0xFF /* AEN Packet */
440 #define NCSI_PKT_AEN_LSC 0x00 /* Link status change */
441 #define NCSI_PKT_AEN_CR 0x01 /* Configuration required */
442 #define NCSI_PKT_AEN_HNCDSC 0x02 /* HNC driver status change */
443
444 #endif /* NCSI_PKT_H */
+0
-192
vendor/libslirp/src/ncsi.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * NC-SI (Network Controller Sideband Interface) "echo" model
3 *
4 * Copyright (C) 2016-2018 IBM Corp.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * 3. Neither the name of the copyright holder nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36 #include "slirp.h"
37
38 #include "ncsi-pkt.h"
39
40 static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
41 {
42 uint32_t checksum = 0;
43 int i;
44
45 /*
46 * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
47 * payload interpreted as a series of 16-bit unsigned integer values.
48 */
49 for (i = 0; i < len; i++) {
50 checksum += htons(data[i]);
51 }
52
53 checksum = (~checksum + 1);
54 return checksum;
55 }
56
57 /* Get Capabilities */
58 static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
59 {
60 struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *)rnh;
61
62 rsp->cap = htonl(~0);
63 rsp->bc_cap = htonl(~0);
64 rsp->mc_cap = htonl(~0);
65 rsp->buf_cap = htonl(~0);
66 rsp->aen_cap = htonl(~0);
67 rsp->vlan_mode = 0xff;
68 rsp->uc_cnt = 2;
69 return 0;
70 }
71
72 /* Get Link status */
73 static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
74 {
75 struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *)rnh;
76
77 rsp->status = htonl(0x1);
78 return 0;
79 }
80
81 /* Get Parameters */
82 static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
83 {
84 struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *)rnh;
85
86 /* no MAC address filters or VLAN filters on the channel */
87 rsp->mac_cnt = 0;
88 rsp->mac_enable = 0;
89 rsp->vlan_cnt = 0;
90 rsp->vlan_enable = 0;
91
92 return 0;
93 }
94
95 static const struct ncsi_rsp_handler {
96 unsigned char type;
97 int payload;
98 int (*handler)(struct ncsi_rsp_pkt_hdr *rnh);
99 } ncsi_rsp_handlers[] = { { NCSI_PKT_RSP_CIS, 4, NULL },
100 { NCSI_PKT_RSP_SP, 4, NULL },
101 { NCSI_PKT_RSP_DP, 4, NULL },
102 { NCSI_PKT_RSP_EC, 4, NULL },
103 { NCSI_PKT_RSP_DC, 4, NULL },
104 { NCSI_PKT_RSP_RC, 4, NULL },
105 { NCSI_PKT_RSP_ECNT, 4, NULL },
106 { NCSI_PKT_RSP_DCNT, 4, NULL },
107 { NCSI_PKT_RSP_AE, 4, NULL },
108 { NCSI_PKT_RSP_SL, 4, NULL },
109 { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls },
110 { NCSI_PKT_RSP_SVF, 4, NULL },
111 { NCSI_PKT_RSP_EV, 4, NULL },
112 { NCSI_PKT_RSP_DV, 4, NULL },
113 { NCSI_PKT_RSP_SMA, 4, NULL },
114 { NCSI_PKT_RSP_EBF, 4, NULL },
115 { NCSI_PKT_RSP_DBF, 4, NULL },
116 { NCSI_PKT_RSP_EGMF, 4, NULL },
117 { NCSI_PKT_RSP_DGMF, 4, NULL },
118 { NCSI_PKT_RSP_SNFC, 4, NULL },
119 { NCSI_PKT_RSP_GVI, 40, NULL },
120 { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc },
121 { NCSI_PKT_RSP_GP, 40, ncsi_rsp_handler_gp },
122 { NCSI_PKT_RSP_GCPS, 172, NULL },
123 { NCSI_PKT_RSP_GNS, 172, NULL },
124 { NCSI_PKT_RSP_GNPTS, 172, NULL },
125 { NCSI_PKT_RSP_GPS, 8, NULL },
126 { NCSI_PKT_RSP_OEM, 0, NULL },
127 { NCSI_PKT_RSP_PLDM, 0, NULL },
128 { NCSI_PKT_RSP_GPUUID, 20, NULL } };
129
130 /*
131 * packet format : ncsi header + payload + checksum
132 */
133 #define NCSI_MAX_PAYLOAD 172
134 #define NCSI_MAX_LEN (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4)
135
136 void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
137 {
138 struct ncsi_pkt_hdr *nh = (struct ncsi_pkt_hdr *)(pkt + ETH_HLEN);
139 uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN];
140 struct ethhdr *reh = (struct ethhdr *)ncsi_reply;
141 struct ncsi_rsp_pkt_hdr *rnh =
142 (struct ncsi_rsp_pkt_hdr *)(ncsi_reply + ETH_HLEN);
143 const struct ncsi_rsp_handler *handler = NULL;
144 int i;
145 int ncsi_rsp_len = sizeof(*nh);
146 uint32_t checksum;
147 uint32_t *pchecksum;
148
149 memset(ncsi_reply, 0, sizeof(ncsi_reply));
150
151 memset(reh->h_dest, 0xff, ETH_ALEN);
152 memset(reh->h_source, 0xff, ETH_ALEN);
153 reh->h_proto = htons(ETH_P_NCSI);
154
155 for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) {
156 if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
157 handler = &ncsi_rsp_handlers[i];
158 break;
159 }
160 }
161
162 rnh->common.mc_id = nh->mc_id;
163 rnh->common.revision = NCSI_PKT_REVISION;
164 rnh->common.id = nh->id;
165 rnh->common.type = nh->type + 0x80;
166 rnh->common.channel = nh->channel;
167
168 if (handler) {
169 rnh->common.length = htons(handler->payload);
170 rnh->code = htons(NCSI_PKT_RSP_C_COMPLETED);
171 rnh->reason = htons(NCSI_PKT_RSP_R_NO_ERROR);
172
173 if (handler->handler) {
174 /* TODO: handle errors */
175 handler->handler(rnh);
176 }
177 ncsi_rsp_len += handler->payload;
178 } else {
179 rnh->common.length = 0;
180 rnh->code = htons(NCSI_PKT_RSP_C_UNAVAILABLE);
181 rnh->reason = htons(NCSI_PKT_RSP_R_UNKNOWN);
182 }
183
184 /* Add the optional checksum at the end of the frame. */
185 checksum = ncsi_calculate_checksum((uint16_t *)rnh, ncsi_rsp_len);
186 pchecksum = (uint32_t *)((void *)rnh + ncsi_rsp_len);
187 *pchecksum = htonl(checksum);
188 ncsi_rsp_len += 4;
189
190 slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
191 }
+0
-87
vendor/libslirp/src/ndp_table.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #include "slirp.h"
7
8 void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
9 uint8_t ethaddr[ETH_ALEN])
10 {
11 char addrstr[INET6_ADDRSTRLEN];
12 NdpTable *ndp_table = &slirp->ndp_table;
13 int i;
14
15 inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
16
17 DEBUG_CALL("ndp_table_add");
18 DEBUG_ARG("ip = %s", addrstr);
19 DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1],
20 ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
21
22 if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) {
23 /* Do not register multicast or unspecified addresses */
24 DEBUG_CALL(" abort: do not register multicast or unspecified address");
25 return;
26 }
27
28 /* Search for an entry */
29 for (i = 0; i < NDP_TABLE_SIZE; i++) {
30 if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
31 DEBUG_CALL(" already in table: update the entry");
32 /* Update the entry */
33 memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN);
34 return;
35 }
36 }
37
38 /* No entry found, create a new one */
39 DEBUG_CALL(" create new entry");
40 ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr;
41 memcpy(ndp_table->table[ndp_table->next_victim].eth_addr, ethaddr,
42 ETH_ALEN);
43 ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE;
44 }
45
46 bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
47 uint8_t out_ethaddr[ETH_ALEN])
48 {
49 char addrstr[INET6_ADDRSTRLEN];
50 NdpTable *ndp_table = &slirp->ndp_table;
51 int i;
52
53 inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
54
55 DEBUG_CALL("ndp_table_search");
56 DEBUG_ARG("ip = %s", addrstr);
57
58 assert(!in6_zero(&ip_addr));
59
60 /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
61 if (IN6_IS_ADDR_MULTICAST(&ip_addr)) {
62 out_ethaddr[0] = 0x33;
63 out_ethaddr[1] = 0x33;
64 out_ethaddr[2] = ip_addr.s6_addr[12];
65 out_ethaddr[3] = ip_addr.s6_addr[13];
66 out_ethaddr[4] = ip_addr.s6_addr[14];
67 out_ethaddr[5] = ip_addr.s6_addr[15];
68 DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x",
69 out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
70 out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
71 return 1;
72 }
73
74 for (i = 0; i < NDP_TABLE_SIZE; i++) {
75 if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
76 memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN);
77 DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
78 out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
79 out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
80 return 1;
81 }
82 }
83
84 DEBUG_CALL(" ip not found in table");
85 return 0;
86 }
+0
-186
vendor/libslirp/src/sbuf.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #include "slirp.h"
6
7 static void sbappendsb(struct sbuf *sb, struct mbuf *m);
8
9 void sbfree(struct sbuf *sb)
10 {
11 free(sb->sb_data);
12 }
13
14 bool sbdrop(struct sbuf *sb, int num)
15 {
16 int limit = sb->sb_datalen / 2;
17
18 /*
19 * We can only drop how much we have
20 * This should never succeed
21 */
22 if (num > sb->sb_cc)
23 num = sb->sb_cc;
24 sb->sb_cc -= num;
25 sb->sb_rptr += num;
26 if (sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
27 sb->sb_rptr -= sb->sb_datalen;
28
29 if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
30 return true;
31 }
32
33 return false;
34 }
35
36 void sbreserve(struct sbuf *sb, int size)
37 {
38 if (sb->sb_data) {
39 /* Already alloced, realloc if necessary */
40 if (sb->sb_datalen != size) {
41 sb->sb_wptr = sb->sb_rptr = sb->sb_data =
42 (char *)realloc(sb->sb_data, size);
43 sb->sb_cc = 0;
44 if (sb->sb_wptr)
45 sb->sb_datalen = size;
46 else
47 sb->sb_datalen = 0;
48 }
49 } else {
50 sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
51 sb->sb_cc = 0;
52 if (sb->sb_wptr)
53 sb->sb_datalen = size;
54 else
55 sb->sb_datalen = 0;
56 }
57 }
58
59 /*
60 * Try and write() to the socket, whatever doesn't get written
61 * append to the buffer... for a host with a fast net connection,
62 * this prevents an unnecessary copy of the data
63 * (the socket is non-blocking, so we won't hang)
64 */
65 void sbappend(struct socket *so, struct mbuf *m)
66 {
67 int ret = 0;
68
69 DEBUG_CALL("sbappend");
70 DEBUG_ARG("so = %p", so);
71 DEBUG_ARG("m = %p", m);
72 DEBUG_ARG("m->m_len = %d", m->m_len);
73
74 /* Shouldn't happen, but... e.g. foreign host closes connection */
75 if (m->m_len <= 0) {
76 m_free(m);
77 return;
78 }
79
80 /*
81 * If there is urgent data, call sosendoob
82 * if not all was sent, sowrite will take care of the rest
83 * (The rest of this function is just an optimisation)
84 */
85 if (so->so_urgc) {
86 sbappendsb(&so->so_rcv, m);
87 m_free(m);
88 (void)sosendoob(so);
89 return;
90 }
91
92 /*
93 * We only write if there's nothing in the buffer,
94 * ottherwise it'll arrive out of order, and hence corrupt
95 */
96 if (!so->so_rcv.sb_cc)
97 ret = slirp_send(so, m->m_data, m->m_len, 0);
98
99 if (ret <= 0) {
100 /*
101 * Nothing was written
102 * It's possible that the socket has closed, but
103 * we don't need to check because if it has closed,
104 * it will be detected in the normal way by soread()
105 */
106 sbappendsb(&so->so_rcv, m);
107 } else if (ret != m->m_len) {
108 /*
109 * Something was written, but not everything..
110 * sbappendsb the rest
111 */
112 m->m_len -= ret;
113 m->m_data += ret;
114 sbappendsb(&so->so_rcv, m);
115 } /* else */
116 /* Whatever happened, we free the mbuf */
117 m_free(m);
118 }
119
120 /*
121 * Copy the data from m into sb
122 * The caller is responsible to make sure there's enough room
123 */
124 static void sbappendsb(struct sbuf *sb, struct mbuf *m)
125 {
126 int len, n, nn;
127
128 len = m->m_len;
129
130 if (sb->sb_wptr < sb->sb_rptr) {
131 n = sb->sb_rptr - sb->sb_wptr;
132 if (n > len)
133 n = len;
134 memcpy(sb->sb_wptr, m->m_data, n);
135 } else {
136 /* Do the right edge first */
137 n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
138 if (n > len)
139 n = len;
140 memcpy(sb->sb_wptr, m->m_data, n);
141 len -= n;
142 if (len) {
143 /* Now the left edge */
144 nn = sb->sb_rptr - sb->sb_data;
145 if (nn > len)
146 nn = len;
147 memcpy(sb->sb_data, m->m_data + n, nn);
148 n += nn;
149 }
150 }
151
152 sb->sb_cc += n;
153 sb->sb_wptr += n;
154 if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
155 sb->sb_wptr -= sb->sb_datalen;
156 }
157
158 /*
159 * Copy data from sbuf to a normal, straight buffer
160 * Don't update the sbuf rptr, this will be
161 * done in sbdrop when the data is acked
162 */
163 void sbcopy(struct sbuf *sb, int off, int len, char *to)
164 {
165 char *from;
166
167 from = sb->sb_rptr + off;
168 if (from >= sb->sb_data + sb->sb_datalen)
169 from -= sb->sb_datalen;
170
171 if (from < sb->sb_wptr) {
172 if (len > sb->sb_cc)
173 len = sb->sb_cc;
174 memcpy(to, from, len);
175 } else {
176 /* re-use off */
177 off = (sb->sb_data + sb->sb_datalen) - from;
178 if (off > len)
179 off = len;
180 memcpy(to, from, off);
181 len -= off;
182 if (len)
183 memcpy(to + off, sb->sb_data, len);
184 }
185 }
+0
-27
vendor/libslirp/src/sbuf.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #ifndef SBUF_H
6 #define SBUF_H
7
8 #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
9
10 struct sbuf {
11 uint32_t sb_cc; /* actual chars in buffer */
12 uint32_t sb_datalen; /* Length of data */
13 char *sb_wptr; /* write pointer. points to where the next
14 * bytes should be written in the sbuf */
15 char *sb_rptr; /* read pointer. points to where the next
16 * byte should be read from the sbuf */
17 char *sb_data; /* Actual data */
18 };
19
20 void sbfree(struct sbuf *);
21 bool sbdrop(struct sbuf *, int);
22 void sbreserve(struct sbuf *, int);
23 void sbappend(struct socket *, struct mbuf *);
24 void sbcopy(struct sbuf *, int, int, char *);
25
26 #endif
+0
-1151
vendor/libslirp/src/slirp.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * libslirp glue
3 *
4 * Copyright (c) 2004-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "slirp.h"
25
26
27 #ifndef _WIN32
28 #include <net/if.h>
29 #endif
30
31 int slirp_debug;
32
33 /* Define to 1 if you want KEEPALIVE timers */
34 bool slirp_do_keepalive;
35
36 /* host loopback address */
37 struct in_addr loopback_addr;
38 /* host loopback network mask */
39 unsigned long loopback_mask;
40
41 /* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
42 static const uint8_t special_ethaddr[ETH_ALEN] = { 0x52, 0x55, 0x00,
43 0x00, 0x00, 0x00 };
44
45 unsigned curtime;
46
47 static struct in_addr dns_addr;
48 #ifndef _WIN32
49 static struct in6_addr dns6_addr;
50 #endif
51 static unsigned dns_addr_time;
52 #ifndef _WIN32
53 static unsigned dns6_addr_time;
54 #endif
55
56 #define TIMEOUT_FAST 2 /* milliseconds */
57 #define TIMEOUT_SLOW 499 /* milliseconds */
58 /* for the aging of certain requests like DNS */
59 #define TIMEOUT_DEFAULT 1000 /* milliseconds */
60
61 #ifdef _WIN32
62
63 int get_dns_addr(struct in_addr *pdns_addr)
64 {
65 FIXED_INFO *FixedInfo = NULL;
66 ULONG BufLen;
67 DWORD ret;
68 IP_ADDR_STRING *pIPAddr;
69 struct in_addr tmp_addr;
70
71 if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
72 *pdns_addr = dns_addr;
73 return 0;
74 }
75
76 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
77 BufLen = sizeof(FIXED_INFO);
78
79 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
80 if (FixedInfo) {
81 GlobalFree(FixedInfo);
82 FixedInfo = NULL;
83 }
84 FixedInfo = GlobalAlloc(GPTR, BufLen);
85 }
86
87 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
88 printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret);
89 if (FixedInfo) {
90 GlobalFree(FixedInfo);
91 FixedInfo = NULL;
92 }
93 return -1;
94 }
95
96 pIPAddr = &(FixedInfo->DnsServerList);
97 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
98 *pdns_addr = tmp_addr;
99 dns_addr = tmp_addr;
100 dns_addr_time = curtime;
101 if (FixedInfo) {
102 GlobalFree(FixedInfo);
103 FixedInfo = NULL;
104 }
105 return 0;
106 }
107
108 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
109 {
110 return -1;
111 }
112
113 static void winsock_cleanup(void)
114 {
115 WSACleanup();
116 }
117
118 #else
119
120 static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
121 socklen_t addrlen, struct stat *cached_stat,
122 unsigned *cached_time)
123 {
124 struct stat old_stat;
125 if (curtime - *cached_time < TIMEOUT_DEFAULT) {
126 memcpy(pdns_addr, cached_addr, addrlen);
127 return 0;
128 }
129 old_stat = *cached_stat;
130 if (stat("/etc/resolv.conf", cached_stat) != 0) {
131 return -1;
132 }
133 if (cached_stat->st_dev == old_stat.st_dev &&
134 cached_stat->st_ino == old_stat.st_ino &&
135 cached_stat->st_size == old_stat.st_size &&
136 cached_stat->st_mtime == old_stat.st_mtime) {
137 memcpy(pdns_addr, cached_addr, addrlen);
138 return 0;
139 }
140 return 1;
141 }
142
143 static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
144 socklen_t addrlen, uint32_t *scope_id,
145 unsigned *cached_time)
146 {
147 char buff[512];
148 char buff2[257];
149 FILE *f;
150 int found = 0;
151 void *tmp_addr = alloca(addrlen);
152 unsigned if_index;
153
154 f = fopen("/etc/resolv.conf", "r");
155 if (!f)
156 return -1;
157
158 DEBUG_MISC("IP address of your DNS(s):");
159 while (fgets(buff, 512, f) != NULL) {
160 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
161 char *c = strchr(buff2, '%');
162 if (c) {
163 if_index = if_nametoindex(c + 1);
164 *c = '\0';
165 } else {
166 if_index = 0;
167 }
168
169 if (!inet_pton(af, buff2, tmp_addr)) {
170 continue;
171 }
172 /* If it's the first one, set it to dns_addr */
173 if (!found) {
174 memcpy(pdns_addr, tmp_addr, addrlen);
175 memcpy(cached_addr, tmp_addr, addrlen);
176 if (scope_id) {
177 *scope_id = if_index;
178 }
179 *cached_time = curtime;
180 }
181
182 if (++found > 3) {
183 DEBUG_MISC(" (more)");
184 break;
185 } else if (slirp_debug & DBG_MISC) {
186 char s[INET6_ADDRSTRLEN];
187 const char *res = inet_ntop(af, tmp_addr, s, sizeof(s));
188 if (!res) {
189 res = " (string conversion error)";
190 }
191 DEBUG_MISC(" %s", res);
192 }
193 }
194 }
195 fclose(f);
196 if (!found)
197 return -1;
198 return 0;
199 }
200
201 int get_dns_addr(struct in_addr *pdns_addr)
202 {
203 static struct stat dns_addr_stat;
204
205 if (dns_addr.s_addr != 0) {
206 int ret;
207 ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr),
208 &dns_addr_stat, &dns_addr_time);
209 if (ret <= 0) {
210 return ret;
211 }
212 }
213 return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr,
214 sizeof(dns_addr), NULL, &dns_addr_time);
215 }
216
217 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
218 {
219 static struct stat dns6_addr_stat;
220
221 if (!in6_zero(&dns6_addr)) {
222 int ret;
223 ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr),
224 &dns6_addr_stat, &dns6_addr_time);
225 if (ret <= 0) {
226 return ret;
227 }
228 }
229 return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr,
230 sizeof(dns6_addr), scope_id,
231 &dns6_addr_time);
232 }
233
234 #endif
235
236 static void slirp_init_once(void)
237 {
238 static int initialized;
239 const char *debug;
240 #ifdef _WIN32
241 WSADATA Data;
242 #endif
243
244 if (initialized) {
245 return;
246 }
247 initialized = 1;
248
249 #ifdef _WIN32
250 WSAStartup(MAKEWORD(2, 0), &Data);
251 atexit(winsock_cleanup);
252 #endif
253
254 loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
255 loopback_mask = htonl(IN_CLASSA_NET);
256
257 debug = g_getenv("SLIRP_DEBUG");
258 if (debug) {
259 const GDebugKey keys[] = {
260 { "call", DBG_CALL },
261 { "misc", DBG_MISC },
262 { "error", DBG_ERROR },
263 { "tftp", DBG_TFTP },
264 };
265 slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
266 }
267 }
268
269 Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
270 {
271 Slirp *slirp;
272
273 g_return_val_if_fail(cfg != NULL, NULL);
274 g_return_val_if_fail(cfg->version >= SLIRP_CONFIG_VERSION_MIN, NULL);
275 g_return_val_if_fail(cfg->version <= SLIRP_CONFIG_VERSION_MAX, NULL);
276 g_return_val_if_fail(cfg->if_mtu >= IF_MTU_MIN || cfg->if_mtu == 0, NULL);
277 g_return_val_if_fail(cfg->if_mtu <= IF_MTU_MAX, NULL);
278 g_return_val_if_fail(cfg->if_mru >= IF_MRU_MIN || cfg->if_mru == 0, NULL);
279 g_return_val_if_fail(cfg->if_mru <= IF_MRU_MAX, NULL);
280
281 slirp = g_malloc0(sizeof(Slirp));
282
283 slirp_init_once();
284
285 slirp->opaque = opaque;
286 slirp->cb = callbacks;
287 slirp->grand = g_rand_new();
288 slirp->restricted = cfg->restricted;
289
290 slirp->in_enabled = cfg->in_enabled;
291 slirp->in6_enabled = cfg->in6_enabled;
292
293 if_init(slirp);
294 ip_init(slirp);
295 ip6_init(slirp);
296
297 m_init(slirp);
298
299 slirp->vnetwork_addr = cfg->vnetwork;
300 slirp->vnetwork_mask = cfg->vnetmask;
301 slirp->vhost_addr = cfg->vhost;
302 slirp->vprefix_addr6 = cfg->vprefix_addr6;
303 slirp->vprefix_len = cfg->vprefix_len;
304 slirp->vhost_addr6 = cfg->vhost6;
305 if (cfg->vhostname) {
306 slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
307 cfg->vhostname);
308 }
309 slirp->tftp_prefix = g_strdup(cfg->tftp_path);
310 slirp->bootp_filename = g_strdup(cfg->bootfile);
311 slirp->vdomainname = g_strdup(cfg->vdomainname);
312 slirp->vdhcp_startaddr = cfg->vdhcp_start;
313 slirp->vnameserver_addr = cfg->vnameserver;
314 slirp->vnameserver_addr6 = cfg->vnameserver6;
315 slirp->tftp_server_name = g_strdup(cfg->tftp_server_name);
316
317 if (cfg->vdnssearch) {
318 translate_dnssearch(slirp, cfg->vdnssearch);
319 }
320 slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
321 slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
322 slirp->disable_host_loopback = cfg->disable_host_loopback;
323 slirp->enable_emu = cfg->enable_emu;
324
325 return slirp;
326 }
327
328 Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
329 struct in_addr vnetmask, struct in_addr vhost,
330 bool in6_enabled, struct in6_addr vprefix_addr6,
331 uint8_t vprefix_len, struct in6_addr vhost6,
332 const char *vhostname, const char *tftp_server_name,
333 const char *tftp_path, const char *bootfile,
334 struct in_addr vdhcp_start, struct in_addr vnameserver,
335 struct in6_addr vnameserver6, const char **vdnssearch,
336 const char *vdomainname, const SlirpCb *callbacks,
337 void *opaque)
338 {
339 SlirpConfig cfg;
340 memset(&cfg, 0, sizeof(cfg));
341 cfg.version = 1;
342 cfg.restricted = restricted;
343 cfg.in_enabled = in_enabled;
344 cfg.vnetwork = vnetwork;
345 cfg.vnetmask = vnetmask;
346 cfg.vhost = vhost;
347 cfg.in6_enabled = in6_enabled;
348 cfg.vprefix_addr6 = vprefix_addr6;
349 cfg.vprefix_len = vprefix_len;
350 cfg.vhost6 = vhost6;
351 cfg.vhostname = vhostname;
352 cfg.tftp_server_name = tftp_server_name;
353 cfg.tftp_path = tftp_path;
354 cfg.bootfile = bootfile;
355 cfg.vdhcp_start = vdhcp_start;
356 cfg.vnameserver = vnameserver;
357 cfg.vnameserver6 = vnameserver6;
358 cfg.vdnssearch = vdnssearch;
359 cfg.vdomainname = vdomainname;
360 return slirp_new(&cfg, callbacks, opaque);
361 }
362
363 void slirp_cleanup(Slirp *slirp)
364 {
365 struct gfwd_list *e, *next;
366
367 for (e = slirp->guestfwd_list; e; e = next) {
368 next = e->ex_next;
369 g_free(e->ex_exec);
370 g_free(e);
371 }
372
373 ip_cleanup(slirp);
374 ip6_cleanup(slirp);
375 m_cleanup(slirp);
376
377 g_rand_free(slirp->grand);
378
379 g_free(slirp->vdnssearch);
380 g_free(slirp->tftp_prefix);
381 g_free(slirp->bootp_filename);
382 g_free(slirp->vdomainname);
383 g_free(slirp);
384 }
385
386 #define CONN_CANFSEND(so) \
387 (((so)->so_state & (SS_FCANTSENDMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED)
388 #define CONN_CANFRCV(so) \
389 (((so)->so_state & (SS_FCANTRCVMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED)
390
391 static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
392 {
393 uint32_t t;
394
395 if (*timeout <= TIMEOUT_FAST) {
396 return;
397 }
398
399 t = MIN(1000, *timeout);
400
401 /* If we have tcp timeout with slirp, then we will fill @timeout with
402 * more precise value.
403 */
404 if (slirp->time_fasttimo) {
405 *timeout = TIMEOUT_FAST;
406 return;
407 }
408 if (slirp->do_slowtimo) {
409 t = MIN(TIMEOUT_SLOW, t);
410 }
411 *timeout = t;
412 }
413
414 void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
415 SlirpAddPollCb add_poll, void *opaque)
416 {
417 struct socket *so, *so_next;
418
419 /*
420 * First, TCP sockets
421 */
422
423 /*
424 * *_slowtimo needs calling if there are IP fragments
425 * in the fragment queue, or there are TCP connections active
426 */
427 slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
428 (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
429
430 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
431 int events = 0;
432
433 so_next = so->so_next;
434
435 so->pollfds_idx = -1;
436
437 /*
438 * See if we need a tcp_fasttimo
439 */
440 if (slirp->time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) {
441 slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
442 }
443
444 /*
445 * NOFDREF can include still connecting to local-host,
446 * newly socreated() sockets etc. Don't want to select these.
447 */
448 if (so->so_state & SS_NOFDREF || so->s == -1) {
449 continue;
450 }
451
452 /*
453 * Set for reading sockets which are accepting
454 */
455 if (so->so_state & SS_FACCEPTCONN) {
456 so->pollfds_idx = add_poll(
457 so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
458 continue;
459 }
460
461 /*
462 * Set for writing sockets which are connecting
463 */
464 if (so->so_state & SS_ISFCONNECTING) {
465 so->pollfds_idx =
466 add_poll(so->s, SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque);
467 continue;
468 }
469
470 /*
471 * Set for writing if we are connected, can send more, and
472 * we have something to send
473 */
474 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
475 events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR;
476 }
477
478 /*
479 * Set for reading (and urgent data) if we are connected, can
480 * receive more, and we have room for it XXX /2 ?
481 */
482 if (CONN_CANFRCV(so) &&
483 (so->so_snd.sb_cc < (so->so_snd.sb_datalen / 2))) {
484 events |= SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR |
485 SLIRP_POLL_PRI;
486 }
487
488 if (events) {
489 so->pollfds_idx = add_poll(so->s, events, opaque);
490 }
491 }
492
493 /*
494 * UDP sockets
495 */
496 for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
497 so_next = so->so_next;
498
499 so->pollfds_idx = -1;
500
501 /*
502 * See if it's timed out
503 */
504 if (so->so_expire) {
505 if (so->so_expire <= curtime) {
506 udp_detach(so);
507 continue;
508 } else {
509 slirp->do_slowtimo = true; /* Let socket expire */
510 }
511 }
512
513 /*
514 * When UDP packets are received from over the
515 * link, they're sendto()'d straight away, so
516 * no need for setting for writing
517 * Limit the number of packets queued by this session
518 * to 4. Note that even though we try and limit this
519 * to 4 packets, the session could have more queued
520 * if the packets needed to be fragmented
521 * (XXX <= 4 ?)
522 */
523 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
524 so->pollfds_idx = add_poll(
525 so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
526 }
527 }
528
529 /*
530 * ICMP sockets
531 */
532 for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
533 so_next = so->so_next;
534
535 so->pollfds_idx = -1;
536
537 /*
538 * See if it's timed out
539 */
540 if (so->so_expire) {
541 if (so->so_expire <= curtime) {
542 icmp_detach(so);
543 continue;
544 } else {
545 slirp->do_slowtimo = true; /* Let socket expire */
546 }
547 }
548
549 if (so->so_state & SS_ISFCONNECTED) {
550 so->pollfds_idx = add_poll(
551 so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
552 }
553 }
554
555 slirp_update_timeout(slirp, timeout);
556 }
557
558 void slirp_pollfds_poll(Slirp *slirp, int select_error,
559 SlirpGetREventsCb get_revents, void *opaque)
560 {
561 struct socket *so, *so_next;
562 int ret;
563
564 curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS;
565
566 /*
567 * See if anything has timed out
568 */
569 if (slirp->time_fasttimo &&
570 ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
571 tcp_fasttimo(slirp);
572 slirp->time_fasttimo = 0;
573 }
574 if (slirp->do_slowtimo &&
575 ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
576 ip_slowtimo(slirp);
577 tcp_slowtimo(slirp);
578 slirp->last_slowtimo = curtime;
579 }
580
581 /*
582 * Check sockets
583 */
584 if (!select_error) {
585 /*
586 * Check TCP sockets
587 */
588 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
589 int revents;
590
591 so_next = so->so_next;
592
593 revents = 0;
594 if (so->pollfds_idx != -1) {
595 revents = get_revents(so->pollfds_idx, opaque);
596 }
597
598 if (so->so_state & SS_NOFDREF || so->s == -1) {
599 continue;
600 }
601
602 /*
603 * Check for URG data
604 * This will soread as well, so no need to
605 * test for SLIRP_POLL_IN below if this succeeds
606 */
607 if (revents & SLIRP_POLL_PRI) {
608 ret = sorecvoob(so);
609 if (ret < 0) {
610 /* Socket error might have resulted in the socket being
611 * removed, do not try to do anything more with it. */
612 continue;
613 }
614 }
615 /*
616 * Check sockets for reading
617 */
618 else if (revents &
619 (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) {
620 /*
621 * Check for incoming connections
622 */
623 if (so->so_state & SS_FACCEPTCONN) {
624 tcp_connect(so);
625 continue;
626 } /* else */
627 ret = soread(so);
628
629 /* Output it if we read something */
630 if (ret > 0) {
631 tcp_output(sototcpcb(so));
632 }
633 if (ret < 0) {
634 /* Socket error might have resulted in the socket being
635 * removed, do not try to do anything more with it. */
636 continue;
637 }
638 }
639
640 /*
641 * Check sockets for writing
642 */
643 if (!(so->so_state & SS_NOFDREF) &&
644 (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) {
645 /*
646 * Check for non-blocking, still-connecting sockets
647 */
648 if (so->so_state & SS_ISFCONNECTING) {
649 /* Connected */
650 so->so_state &= ~SS_ISFCONNECTING;
651
652 ret = send(so->s, (const void *)&ret, 0, 0);
653 if (ret < 0) {
654 /* XXXXX Must fix, zero bytes is a NOP */
655 if (errno == EAGAIN || errno == EWOULDBLOCK ||
656 errno == EINPROGRESS || errno == ENOTCONN) {
657 continue;
658 }
659
660 /* else failed */
661 so->so_state &= SS_PERSISTENT_MASK;
662 so->so_state |= SS_NOFDREF;
663 }
664 /* else so->so_state &= ~SS_ISFCONNECTING; */
665
666 /*
667 * Continue tcp_input
668 */
669 tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
670 so->so_ffamily);
671 /* continue; */
672 } else {
673 ret = sowrite(so);
674 if (ret > 0) {
675 /* Call tcp_output in case we need to send a window
676 * update to the guest, otherwise it will be stuck
677 * until it sends a window probe. */
678 tcp_output(sototcpcb(so));
679 }
680 }
681 }
682 }
683
684 /*
685 * Now UDP sockets.
686 * Incoming packets are sent straight away, they're not buffered.
687 * Incoming UDP data isn't buffered either.
688 */
689 for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
690 int revents;
691
692 so_next = so->so_next;
693
694 revents = 0;
695 if (so->pollfds_idx != -1) {
696 revents = get_revents(so->pollfds_idx, opaque);
697 }
698
699 if (so->s != -1 &&
700 (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
701 sorecvfrom(so);
702 }
703 }
704
705 /*
706 * Check incoming ICMP relies.
707 */
708 for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
709 int revents;
710
711 so_next = so->so_next;
712
713 revents = 0;
714 if (so->pollfds_idx != -1) {
715 revents = get_revents(so->pollfds_idx, opaque);
716 }
717
718 if (so->s != -1 &&
719 (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
720 icmp_receive(so);
721 }
722 }
723 }
724
725 if_start(slirp);
726 }
727
728 static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
729 {
730 struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN);
731 uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
732 struct ethhdr *reh = (struct ethhdr *)arp_reply;
733 struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
734 int ar_op;
735 struct gfwd_list *ex_ptr;
736
737 if (!slirp->in_enabled) {
738 return;
739 }
740
741 ar_op = ntohs(ah->ar_op);
742 switch (ar_op) {
743 case ARPOP_REQUEST:
744 if (ah->ar_tip == ah->ar_sip) {
745 /* Gratuitous ARP */
746 arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
747 return;
748 }
749
750 if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
751 slirp->vnetwork_addr.s_addr) {
752 if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
753 ah->ar_tip == slirp->vhost_addr.s_addr)
754 goto arp_ok;
755 /* TODO: IPv6 */
756 for (ex_ptr = slirp->guestfwd_list; ex_ptr;
757 ex_ptr = ex_ptr->ex_next) {
758 if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
759 goto arp_ok;
760 }
761 return;
762 arp_ok:
763 memset(arp_reply, 0, sizeof(arp_reply));
764
765 arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
766
767 /* ARP request for alias/dns mac address */
768 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
769 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
770 memcpy(&reh->h_source[2], &ah->ar_tip, 4);
771 reh->h_proto = htons(ETH_P_ARP);
772
773 rah->ar_hrd = htons(1);
774 rah->ar_pro = htons(ETH_P_IP);
775 rah->ar_hln = ETH_ALEN;
776 rah->ar_pln = 4;
777 rah->ar_op = htons(ARPOP_REPLY);
778 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
779 rah->ar_sip = ah->ar_tip;
780 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
781 rah->ar_tip = ah->ar_sip;
782 slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply));
783 }
784 break;
785 case ARPOP_REPLY:
786 arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
787 break;
788 default:
789 break;
790 }
791 }
792
793 void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
794 {
795 struct mbuf *m;
796 int proto;
797
798 if (pkt_len < ETH_HLEN)
799 return;
800
801 proto = (((uint16_t)pkt[12]) << 8) + pkt[13];
802 switch (proto) {
803 case ETH_P_ARP:
804 arp_input(slirp, pkt, pkt_len);
805 break;
806 case ETH_P_IP:
807 case ETH_P_IPV6:
808 m = m_get(slirp);
809 if (!m)
810 return;
811 /* Note: we add 2 to align the IP header on 4 bytes,
812 * and add the margin for the tcpiphdr overhead */
813 if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
814 m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
815 }
816 m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
817 memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
818
819 m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
820 m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
821
822 if (proto == ETH_P_IP) {
823 ip_input(m);
824 } else if (proto == ETH_P_IPV6) {
825 ip6_input(m);
826 }
827 break;
828
829 case ETH_P_NCSI:
830 ncsi_input(slirp, pkt, pkt_len);
831 break;
832
833 default:
834 break;
835 }
836 }
837
838 /* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
839 * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
840 * is ready to go.
841 */
842 static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
843 uint8_t ethaddr[ETH_ALEN])
844 {
845 const struct ip *iph = (const struct ip *)ifm->m_data;
846
847 if (iph->ip_dst.s_addr == 0) {
848 /* 0.0.0.0 can not be a destination address, something went wrong,
849 * avoid making it worse */
850 return 1;
851 }
852 if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
853 uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)];
854 struct ethhdr *reh = (struct ethhdr *)arp_req;
855 struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN);
856
857 if (!ifm->resolution_requested) {
858 /* If the client addr is not known, send an ARP request */
859 memset(reh->h_dest, 0xff, ETH_ALEN);
860 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
861 memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
862 reh->h_proto = htons(ETH_P_ARP);
863 rah->ar_hrd = htons(1);
864 rah->ar_pro = htons(ETH_P_IP);
865 rah->ar_hln = ETH_ALEN;
866 rah->ar_pln = 4;
867 rah->ar_op = htons(ARPOP_REQUEST);
868
869 /* source hw addr */
870 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
871 memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
872
873 /* source IP */
874 rah->ar_sip = slirp->vhost_addr.s_addr;
875
876 /* target hw addr (none) */
877 memset(rah->ar_tha, 0, ETH_ALEN);
878
879 /* target IP */
880 rah->ar_tip = iph->ip_dst.s_addr;
881 slirp->client_ipaddr = iph->ip_dst;
882 slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
883 ifm->resolution_requested = true;
884
885 /* Expire request and drop outgoing packet after 1 second */
886 ifm->expiration_date =
887 slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
888 }
889 return 0;
890 } else {
891 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
892 /* XXX: not correct */
893 memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
894 eh->h_proto = htons(ETH_P_IP);
895
896 /* Send this */
897 return 2;
898 }
899 }
900
901 /* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
902 * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
903 * is ready to go.
904 */
905 static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
906 uint8_t ethaddr[ETH_ALEN])
907 {
908 const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
909 if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
910 if (!ifm->resolution_requested) {
911 ndp_send_ns(slirp, ip6h->ip_dst);
912 ifm->resolution_requested = true;
913 ifm->expiration_date =
914 slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
915 }
916 return 0;
917 } else {
918 eh->h_proto = htons(ETH_P_IPV6);
919 in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
920
921 /* Send this */
922 return 2;
923 }
924 }
925
926 /* Output the IP packet to the ethernet device. Returns 0 if the packet must be
927 * re-queued.
928 */
929 int if_encap(Slirp *slirp, struct mbuf *ifm)
930 {
931 uint8_t buf[IF_MTU_MAX + 100];
932 struct ethhdr *eh = (struct ethhdr *)buf;
933 uint8_t ethaddr[ETH_ALEN];
934 const struct ip *iph = (const struct ip *)ifm->m_data;
935 int ret;
936
937 if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
938 return 1;
939 }
940
941 switch (iph->ip_v) {
942 case IPVERSION:
943 ret = if_encap4(slirp, ifm, eh, ethaddr);
944 if (ret < 2) {
945 return ret;
946 }
947 break;
948
949 case IP6VERSION:
950 ret = if_encap6(slirp, ifm, eh, ethaddr);
951 if (ret < 2) {
952 return ret;
953 }
954 break;
955
956 default:
957 g_assert_not_reached();
958 break;
959 }
960
961 memcpy(eh->h_dest, ethaddr, ETH_ALEN);
962 DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_source[0],
963 eh->h_source[1], eh->h_source[2], eh->h_source[3],
964 eh->h_source[4], eh->h_source[5]);
965 DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_dest[0],
966 eh->h_dest[1], eh->h_dest[2], eh->h_dest[3], eh->h_dest[4],
967 eh->h_dest[5]);
968 memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
969 slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
970 return 1;
971 }
972
973 /* Drop host forwarding rule, return 0 if found. */
974 /* TODO: IPv6 */
975 int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
976 int host_port)
977 {
978 struct socket *so;
979 struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
980 struct sockaddr_in addr;
981 int port = htons(host_port);
982 socklen_t addr_len;
983
984 for (so = head->so_next; so != head; so = so->so_next) {
985 addr_len = sizeof(addr);
986 if ((so->so_state & SS_HOSTFWD) &&
987 getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
988 addr.sin_addr.s_addr == host_addr.s_addr && addr.sin_port == port) {
989 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
990 closesocket(so->s);
991 sofree(so);
992 return 0;
993 }
994 }
995
996 return -1;
997 }
998
999 /* TODO: IPv6 */
1000 int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
1001 int host_port, struct in_addr guest_addr, int guest_port)
1002 {
1003 if (!guest_addr.s_addr) {
1004 guest_addr = slirp->vdhcp_startaddr;
1005 }
1006 if (is_udp) {
1007 if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
1008 guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
1009 return -1;
1010 } else {
1011 if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
1012 guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
1013 return -1;
1014 }
1015 return 0;
1016 }
1017
1018 /* TODO: IPv6 */
1019 static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
1020 int guest_port)
1021 {
1022 struct gfwd_list *tmp_ptr;
1023
1024 if (!guest_addr->s_addr) {
1025 guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
1026 (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
1027 }
1028 if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
1029 slirp->vnetwork_addr.s_addr ||
1030 guest_addr->s_addr == slirp->vhost_addr.s_addr ||
1031 guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
1032 return false;
1033 }
1034
1035 /* check if the port is "bound" */
1036 for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
1037 if (guest_port == tmp_ptr->ex_fport &&
1038 guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
1039 return false;
1040 }
1041
1042 return true;
1043 }
1044
1045 int slirp_add_exec(Slirp *slirp, const char *cmdline,
1046 struct in_addr *guest_addr, int guest_port)
1047 {
1048 if (!check_guestfwd(slirp, guest_addr, guest_port)) {
1049 return -1;
1050 }
1051
1052 add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
1053 return 0;
1054 }
1055
1056 int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
1057 struct in_addr *guest_addr, int guest_port)
1058 {
1059 if (!check_guestfwd(slirp, guest_addr, guest_port)) {
1060 return -1;
1061 }
1062
1063 add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr,
1064 htons(guest_port));
1065 return 0;
1066 }
1067
1068 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
1069 {
1070 if (so->s == -1 && so->guestfwd) {
1071 /* XXX this blocks entire thread. Rewrite to use
1072 * qemu_chr_fe_write and background I/O callbacks */
1073 so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
1074 return len;
1075 }
1076
1077 if (so->s == -1) {
1078 /*
1079 * This should in theory not happen but it is hard to be
1080 * sure because some code paths will end up with so->s == -1
1081 * on a failure but don't dispose of the struct socket.
1082 * Check specifically, so we don't pass -1 to send().
1083 */
1084 errno = EBADF;
1085 return -1;
1086 }
1087
1088 return send(so->s, buf, len, flags);
1089 }
1090
1091 struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
1092 int guest_port)
1093 {
1094 struct socket *so;
1095
1096 /* TODO: IPv6 */
1097 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
1098 if (so->so_faddr.s_addr == guest_addr.s_addr &&
1099 htons(so->so_fport) == guest_port) {
1100 return so;
1101 }
1102 }
1103 return NULL;
1104 }
1105
1106 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
1107 int guest_port)
1108 {
1109 struct iovec iov[2];
1110 struct socket *so;
1111
1112 so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
1113
1114 if (!so || so->so_state & SS_NOFDREF) {
1115 return 0;
1116 }
1117
1118 if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen / 2)) {
1119 return 0;
1120 }
1121
1122 return sopreprbuf(so, iov, NULL);
1123 }
1124
1125 void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
1126 const uint8_t *buf, int size)
1127 {
1128 int ret;
1129 struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
1130
1131 if (!so)
1132 return;
1133
1134 ret = soreadbuf(so, (const char *)buf, size);
1135
1136 if (ret > 0)
1137 tcp_output(sototcpcb(so));
1138 }
1139
1140 void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len)
1141 {
1142 ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque);
1143
1144 if (ret < 0) {
1145 g_critical("Failed to send packet, ret: %ld", (long)ret);
1146 } else if (ret < len) {
1147 DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu", (long)ret,
1148 (unsigned long)len);
1149 }
1150 }
+0
-280
vendor/libslirp/src/slirp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 #ifndef SLIRP_H
2 #define SLIRP_H
3
4 #ifdef _WIN32
5
6 /* as defined in sdkddkver.h */
7 #ifndef _WIN32_WINNT
8 #define _WIN32_WINNT 0x0600 /* Vista */
9 #endif
10 /* reduces the number of implicitly included headers */
11 #ifndef WIN32_LEAN_AND_MEAN
12 #define WIN32_LEAN_AND_MEAN
13 #endif
14
15 #include <winsock2.h>
16 #include <windows.h>
17 #include <ws2tcpip.h>
18 #include <sys/timeb.h>
19 #include <iphlpapi.h>
20
21 #else
22 #if !defined(__HAIKU__)
23 #define O_BINARY 0
24 #endif
25 #endif
26
27 #ifndef _WIN32
28 #include <sys/uio.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #endif
34
35 #ifdef __APPLE__
36 #include <sys/filio.h>
37 #endif
38
39 /* Avoid conflicting with the libc insque() and remque(), which
40 have different prototypes. */
41 #define insque slirp_insque
42 #define remque slirp_remque
43 #define quehead slirp_quehead
44
45 #include "debug.h"
46 #include "util.h"
47
48 #include "libslirp.h"
49 #include "ip.h"
50 #include "ip6.h"
51 #include "tcp.h"
52 #include "tcp_timer.h"
53 #include "tcp_var.h"
54 #include "tcpip.h"
55 #include "udp.h"
56 #include "ip_icmp.h"
57 #include "ip6_icmp.h"
58 #include "mbuf.h"
59 #include "sbuf.h"
60 #include "socket.h"
61 #include "if.h"
62 #include "main.h"
63 #include "misc.h"
64
65 #include "bootp.h"
66 #include "tftp.h"
67
68 #define ARPOP_REQUEST 1 /* ARP request */
69 #define ARPOP_REPLY 2 /* ARP reply */
70
71 struct ethhdr {
72 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
73 unsigned char h_source[ETH_ALEN]; /* source ether addr */
74 unsigned short h_proto; /* packet type ID field */
75 };
76
77 struct slirp_arphdr {
78 unsigned short ar_hrd; /* format of hardware address */
79 unsigned short ar_pro; /* format of protocol address */
80 unsigned char ar_hln; /* length of hardware address */
81 unsigned char ar_pln; /* length of protocol address */
82 unsigned short ar_op; /* ARP opcode (command) */
83
84 /*
85 * Ethernet looks like this : This bit is variable sized however...
86 */
87 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
88 uint32_t ar_sip; /* sender IP address */
89 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
90 uint32_t ar_tip; /* target IP address */
91 } SLIRP_PACKED;
92
93 #define ARP_TABLE_SIZE 16
94
95 typedef struct ArpTable {
96 struct slirp_arphdr table[ARP_TABLE_SIZE];
97 int next_victim;
98 } ArpTable;
99
100 void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
101
102 bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
103 uint8_t out_ethaddr[ETH_ALEN]);
104
105 struct ndpentry {
106 unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */
107 struct in6_addr ip_addr; /* sender IP address */
108 };
109
110 #define NDP_TABLE_SIZE 16
111
112 typedef struct NdpTable {
113 struct ndpentry table[NDP_TABLE_SIZE];
114 int next_victim;
115 } NdpTable;
116
117 void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
118 uint8_t ethaddr[ETH_ALEN]);
119 bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
120 uint8_t out_ethaddr[ETH_ALEN]);
121
122 struct Slirp {
123 unsigned time_fasttimo;
124 unsigned last_slowtimo;
125 bool do_slowtimo;
126
127 bool in_enabled, in6_enabled;
128
129 /* virtual network configuration */
130 struct in_addr vnetwork_addr;
131 struct in_addr vnetwork_mask;
132 struct in_addr vhost_addr;
133 struct in6_addr vprefix_addr6;
134 uint8_t vprefix_len;
135 struct in6_addr vhost_addr6;
136 struct in_addr vdhcp_startaddr;
137 struct in_addr vnameserver_addr;
138 struct in6_addr vnameserver_addr6;
139
140 struct in_addr client_ipaddr;
141 char client_hostname[33];
142
143 int restricted;
144 struct gfwd_list *guestfwd_list;
145
146 int if_mtu;
147 int if_mru;
148
149 bool disable_host_loopback;
150
151 /* mbuf states */
152 struct quehead m_freelist;
153 struct quehead m_usedlist;
154 int mbuf_alloced;
155
156 /* if states */
157 struct quehead if_fastq; /* fast queue (for interactive data) */
158 struct quehead if_batchq; /* queue for non-interactive data */
159 bool if_start_busy; /* avoid if_start recursion */
160
161 /* ip states */
162 struct ipq ipq; /* ip reass. queue */
163 uint16_t ip_id; /* ip packet ctr, for ids */
164
165 /* bootp/dhcp states */
166 BOOTPClient bootp_clients[NB_BOOTP_CLIENTS];
167 char *bootp_filename;
168 size_t vdnssearch_len;
169 uint8_t *vdnssearch;
170 char *vdomainname;
171
172 /* tcp states */
173 struct socket tcb;
174 struct socket *tcp_last_so;
175 tcp_seq tcp_iss; /* tcp initial send seq # */
176 uint32_t tcp_now; /* for RFC 1323 timestamps */
177
178 /* udp states */
179 struct socket udb;
180 struct socket *udp_last_so;
181
182 /* icmp states */
183 struct socket icmp;
184 struct socket *icmp_last_so;
185
186 /* tftp states */
187 char *tftp_prefix;
188 struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
189 char *tftp_server_name;
190
191 ArpTable arp_table;
192 NdpTable ndp_table;
193
194 GRand *grand;
195 void *ra_timer;
196
197 bool enable_emu;
198
199 const SlirpCb *cb;
200 void *opaque;
201 };
202
203 void if_start(Slirp *);
204
205 int get_dns_addr(struct in_addr *pdns_addr);
206 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
207
208 /* ncsi.c */
209 void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
210
211 #ifndef _WIN32
212 #include <netdb.h>
213 #endif
214
215
216 extern bool slirp_do_keepalive;
217
218 #define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
219
220 /* dnssearch.c */
221 int translate_dnssearch(Slirp *s, const char **names);
222
223 /* cksum.c */
224 int cksum(struct mbuf *m, int len);
225 int ip6_cksum(struct mbuf *m);
226
227 /* if.c */
228 void if_init(Slirp *);
229 void if_output(struct socket *, struct mbuf *);
230
231 /* ip_input.c */
232 void ip_init(Slirp *);
233 void ip_cleanup(Slirp *);
234 void ip_input(struct mbuf *);
235 void ip_slowtimo(Slirp *);
236 void ip_stripoptions(register struct mbuf *, struct mbuf *);
237
238 /* ip_output.c */
239 int ip_output(struct socket *, struct mbuf *);
240
241 /* ip6_input.c */
242 void ip6_init(Slirp *);
243 void ip6_cleanup(Slirp *);
244 void ip6_input(struct mbuf *);
245
246 /* ip6_output */
247 int ip6_output(struct socket *, struct mbuf *, int fast);
248
249 /* tcp_input.c */
250 void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af);
251 int tcp_mss(register struct tcpcb *, unsigned);
252
253 /* tcp_output.c */
254 int tcp_output(register struct tcpcb *);
255 void tcp_setpersist(register struct tcpcb *);
256
257 /* tcp_subr.c */
258 void tcp_init(Slirp *);
259 void tcp_cleanup(Slirp *);
260 void tcp_template(struct tcpcb *);
261 void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
262 register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short);
263 struct tcpcb *tcp_newtcpcb(struct socket *);
264 struct tcpcb *tcp_close(register struct tcpcb *);
265 void tcp_sockclosed(struct tcpcb *);
266 int tcp_fconnect(struct socket *, unsigned short af);
267 void tcp_connect(struct socket *);
268 int tcp_attach(struct socket *);
269 uint8_t tcp_tos(struct socket *);
270 int tcp_emu(struct socket *, struct mbuf *);
271 int tcp_ctl(struct socket *);
272 struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
273
274 struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
275 int guest_port);
276
277 void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
278
279 #endif
+0
-945
vendor/libslirp/src/socket.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #include "slirp.h"
6 #include "ip_icmp.h"
7 #ifdef __sun__
8 #include <sys/filio.h>
9 #endif
10
11 static void sofcantrcvmore(struct socket *so);
12 static void sofcantsendmore(struct socket *so);
13
14 struct socket *solookup(struct socket **last, struct socket *head,
15 struct sockaddr_storage *lhost,
16 struct sockaddr_storage *fhost)
17 {
18 struct socket *so = *last;
19
20 /* Optimisation */
21 if (so != head && sockaddr_equal(&(so->lhost.ss), lhost) &&
22 (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
23 return so;
24 }
25
26 for (so = head->so_next; so != head; so = so->so_next) {
27 if (sockaddr_equal(&(so->lhost.ss), lhost) &&
28 (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
29 *last = so;
30 return so;
31 }
32 }
33
34 return (struct socket *)NULL;
35 }
36
37 /*
38 * Create a new socket, initialise the fields
39 * It is the responsibility of the caller to
40 * insque() it into the correct linked-list
41 */
42 struct socket *socreate(Slirp *slirp)
43 {
44 struct socket *so = g_new(struct socket, 1);
45
46 memset(so, 0, sizeof(struct socket));
47 so->so_state = SS_NOFDREF;
48 so->s = -1;
49 so->slirp = slirp;
50 so->pollfds_idx = -1;
51
52 return so;
53 }
54
55 /*
56 * Remove references to so from the given message queue.
57 */
58 static void soqfree(struct socket *so, struct quehead *qh)
59 {
60 struct mbuf *ifq;
61
62 for (ifq = (struct mbuf *)qh->qh_link; (struct quehead *)ifq != qh;
63 ifq = ifq->ifq_next) {
64 if (ifq->ifq_so == so) {
65 struct mbuf *ifm;
66 ifq->ifq_so = NULL;
67 for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) {
68 ifm->ifq_so = NULL;
69 }
70 }
71 }
72 }
73
74 /*
75 * remque and free a socket, clobber cache
76 */
77 void sofree(struct socket *so)
78 {
79 Slirp *slirp = so->slirp;
80
81 soqfree(so, &slirp->if_fastq);
82 soqfree(so, &slirp->if_batchq);
83
84 if (so == slirp->tcp_last_so) {
85 slirp->tcp_last_so = &slirp->tcb;
86 } else if (so == slirp->udp_last_so) {
87 slirp->udp_last_so = &slirp->udb;
88 } else if (so == slirp->icmp_last_so) {
89 slirp->icmp_last_so = &slirp->icmp;
90 }
91 m_free(so->so_m);
92
93 if (so->so_next && so->so_prev)
94 remque(so); /* crashes if so is not in a queue */
95
96 if (so->so_tcpcb) {
97 free(so->so_tcpcb);
98 }
99 g_free(so);
100 }
101
102 size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
103 {
104 int n, lss, total;
105 struct sbuf *sb = &so->so_snd;
106 int len = sb->sb_datalen - sb->sb_cc;
107 int mss = so->so_tcpcb->t_maxseg;
108
109 DEBUG_CALL("sopreprbuf");
110 DEBUG_ARG("so = %p", so);
111
112 if (len <= 0)
113 return 0;
114
115 iov[0].iov_base = sb->sb_wptr;
116 iov[1].iov_base = NULL;
117 iov[1].iov_len = 0;
118 if (sb->sb_wptr < sb->sb_rptr) {
119 iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
120 /* Should never succeed, but... */
121 if (iov[0].iov_len > len)
122 iov[0].iov_len = len;
123 if (iov[0].iov_len > mss)
124 iov[0].iov_len -= iov[0].iov_len % mss;
125 n = 1;
126 } else {
127 iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
128 /* Should never succeed, but... */
129 if (iov[0].iov_len > len)
130 iov[0].iov_len = len;
131 len -= iov[0].iov_len;
132 if (len) {
133 iov[1].iov_base = sb->sb_data;
134 iov[1].iov_len = sb->sb_rptr - sb->sb_data;
135 if (iov[1].iov_len > len)
136 iov[1].iov_len = len;
137 total = iov[0].iov_len + iov[1].iov_len;
138 if (total > mss) {
139 lss = total % mss;
140 if (iov[1].iov_len > lss) {
141 iov[1].iov_len -= lss;
142 n = 2;
143 } else {
144 lss -= iov[1].iov_len;
145 iov[0].iov_len -= lss;
146 n = 1;
147 }
148 } else
149 n = 2;
150 } else {
151 if (iov[0].iov_len > mss)
152 iov[0].iov_len -= iov[0].iov_len % mss;
153 n = 1;
154 }
155 }
156 if (np)
157 *np = n;
158
159 return iov[0].iov_len + (n - 1) * iov[1].iov_len;
160 }
161
162 /*
163 * Read from so's socket into sb_snd, updating all relevant sbuf fields
164 * NOTE: This will only be called if it is select()ed for reading, so
165 * a read() of 0 (or less) means it's disconnected
166 */
167 int soread(struct socket *so)
168 {
169 int n, nn;
170 size_t buf_len;
171 struct sbuf *sb = &so->so_snd;
172 struct iovec iov[2];
173
174 DEBUG_CALL("soread");
175 DEBUG_ARG("so = %p", so);
176
177 /*
178 * No need to check if there's enough room to read.
179 * soread wouldn't have been called if there weren't
180 */
181 buf_len = sopreprbuf(so, iov, &n);
182 assert(buf_len != 0);
183
184 nn = recv(so->s, iov[0].iov_base, iov[0].iov_len, 0);
185 if (nn <= 0) {
186 if (nn < 0 && (errno == EINTR || errno == EAGAIN))
187 return 0;
188 else {
189 int err;
190 socklen_t elen = sizeof err;
191 struct sockaddr_storage addr;
192 struct sockaddr *paddr = (struct sockaddr *)&addr;
193 socklen_t alen = sizeof addr;
194
195 err = errno;
196 if (nn == 0) {
197 if (getpeername(so->s, paddr, &alen) < 0) {
198 err = errno;
199 } else {
200 getsockopt(so->s, SOL_SOCKET, SO_ERROR, &err, &elen);
201 }
202 }
203
204 DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s", nn,
205 errno, strerror(errno));
206 sofcantrcvmore(so);
207
208 if (err == ECONNRESET || err == ECONNREFUSED || err == ENOTCONN ||
209 err == EPIPE) {
210 tcp_drop(sototcpcb(so), err);
211 } else {
212 tcp_sockclosed(sototcpcb(so));
213 }
214 return -1;
215 }
216 }
217
218 /*
219 * If there was no error, try and read the second time round
220 * We read again if n = 2 (ie, there's another part of the buffer)
221 * and we read as much as we could in the first read
222 * We don't test for <= 0 this time, because there legitimately
223 * might not be any more data (since the socket is non-blocking),
224 * a close will be detected on next iteration.
225 * A return of -1 won't (shouldn't) happen, since it didn't happen above
226 */
227 if (n == 2 && nn == iov[0].iov_len) {
228 int ret;
229 ret = recv(so->s, iov[1].iov_base, iov[1].iov_len, 0);
230 if (ret > 0)
231 nn += ret;
232 }
233
234 DEBUG_MISC(" ... read nn = %d bytes", nn);
235
236 /* Update fields */
237 sb->sb_cc += nn;
238 sb->sb_wptr += nn;
239 if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
240 sb->sb_wptr -= sb->sb_datalen;
241 return nn;
242 }
243
244 int soreadbuf(struct socket *so, const char *buf, int size)
245 {
246 int n, nn, copy = size;
247 struct sbuf *sb = &so->so_snd;
248 struct iovec iov[2];
249
250 DEBUG_CALL("soreadbuf");
251 DEBUG_ARG("so = %p", so);
252
253 /*
254 * No need to check if there's enough room to read.
255 * soread wouldn't have been called if there weren't
256 */
257 assert(size > 0);
258 if (sopreprbuf(so, iov, &n) < size)
259 goto err;
260
261 nn = MIN(iov[0].iov_len, copy);
262 memcpy(iov[0].iov_base, buf, nn);
263
264 copy -= nn;
265 buf += nn;
266
267 if (copy == 0)
268 goto done;
269
270 memcpy(iov[1].iov_base, buf, copy);
271
272 done:
273 /* Update fields */
274 sb->sb_cc += size;
275 sb->sb_wptr += size;
276 if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
277 sb->sb_wptr -= sb->sb_datalen;
278 return size;
279 err:
280
281 sofcantrcvmore(so);
282 tcp_sockclosed(sototcpcb(so));
283 g_critical("soreadbuf buffer too small");
284 return -1;
285 }
286
287 /*
288 * Get urgent data
289 *
290 * When the socket is created, we set it SO_OOBINLINE,
291 * so when OOB data arrives, we soread() it and everything
292 * in the send buffer is sent as urgent data
293 */
294 int sorecvoob(struct socket *so)
295 {
296 struct tcpcb *tp = sototcpcb(so);
297 int ret;
298
299 DEBUG_CALL("sorecvoob");
300 DEBUG_ARG("so = %p", so);
301
302 /*
303 * We take a guess at how much urgent data has arrived.
304 * In most situations, when urgent data arrives, the next
305 * read() should get all the urgent data. This guess will
306 * be wrong however if more data arrives just after the
307 * urgent data, or the read() doesn't return all the
308 * urgent data.
309 */
310 ret = soread(so);
311 if (ret > 0) {
312 tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
313 tp->t_force = 1;
314 tcp_output(tp);
315 tp->t_force = 0;
316 }
317
318 return ret;
319 }
320
321 /*
322 * Send urgent data
323 * There's a lot duplicated code here, but...
324 */
325 int sosendoob(struct socket *so)
326 {
327 struct sbuf *sb = &so->so_rcv;
328 char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
329
330 int n;
331
332 DEBUG_CALL("sosendoob");
333 DEBUG_ARG("so = %p", so);
334 DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
335
336 if (so->so_urgc > 2048)
337 so->so_urgc = 2048; /* XXXX */
338
339 if (sb->sb_rptr < sb->sb_wptr) {
340 /* We can send it directly */
341 n = slirp_send(so, sb->sb_rptr, so->so_urgc,
342 (MSG_OOB)); /* |MSG_DONTWAIT)); */
343 } else {
344 /*
345 * Since there's no sendv or sendtov like writev,
346 * we must copy all data to a linear buffer then
347 * send it all
348 */
349 uint32_t urgc = so->so_urgc;
350 int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
351 if (len > urgc) {
352 len = urgc;
353 }
354 memcpy(buff, sb->sb_rptr, len);
355 urgc -= len;
356 if (urgc) {
357 n = sb->sb_wptr - sb->sb_data;
358 if (n > urgc) {
359 n = urgc;
360 }
361 memcpy((buff + len), sb->sb_data, n);
362 len += n;
363 }
364 n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
365 #ifdef DEBUG
366 if (n != len) {
367 DEBUG_ERROR("Didn't send all data urgently XXXXX");
368 }
369 #endif
370 }
371
372 if (n < 0) {
373 return n;
374 }
375 so->so_urgc -= n;
376 DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n,
377 so->so_urgc);
378
379 sb->sb_cc -= n;
380 sb->sb_rptr += n;
381 if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
382 sb->sb_rptr -= sb->sb_datalen;
383
384 return n;
385 }
386
387 /*
388 * Write data from so_rcv to so's socket,
389 * updating all sbuf field as necessary
390 */
391 int sowrite(struct socket *so)
392 {
393 int n, nn;
394 struct sbuf *sb = &so->so_rcv;
395 int len = sb->sb_cc;
396 struct iovec iov[2];
397
398 DEBUG_CALL("sowrite");
399 DEBUG_ARG("so = %p", so);
400
401 if (so->so_urgc) {
402 uint32_t expected = so->so_urgc;
403 if (sosendoob(so) < expected) {
404 /* Treat a short write as a fatal error too,
405 * rather than continuing on and sending the urgent
406 * data as if it were non-urgent and leaving the
407 * so_urgc count wrong.
408 */
409 goto err_disconnected;
410 }
411 if (sb->sb_cc == 0)
412 return 0;
413 }
414
415 /*
416 * No need to check if there's something to write,
417 * sowrite wouldn't have been called otherwise
418 */
419
420 iov[0].iov_base = sb->sb_rptr;
421 iov[1].iov_base = NULL;
422 iov[1].iov_len = 0;
423 if (sb->sb_rptr < sb->sb_wptr) {
424 iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
425 /* Should never succeed, but... */
426 if (iov[0].iov_len > len)
427 iov[0].iov_len = len;
428 n = 1;
429 } else {
430 iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
431 if (iov[0].iov_len > len)
432 iov[0].iov_len = len;
433 len -= iov[0].iov_len;
434 if (len) {
435 iov[1].iov_base = sb->sb_data;
436 iov[1].iov_len = sb->sb_wptr - sb->sb_data;
437 if (iov[1].iov_len > len)
438 iov[1].iov_len = len;
439 n = 2;
440 } else
441 n = 1;
442 }
443 /* Check if there's urgent data to send, and if so, send it */
444
445 nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len, 0);
446 /* This should never happen, but people tell me it does *shrug* */
447 if (nn < 0 && (errno == EAGAIN || errno == EINTR))
448 return 0;
449
450 if (nn <= 0) {
451 goto err_disconnected;
452 }
453
454 if (n == 2 && nn == iov[0].iov_len) {
455 int ret;
456 ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len, 0);
457 if (ret > 0)
458 nn += ret;
459 }
460 DEBUG_MISC(" ... wrote nn = %d bytes", nn);
461
462 /* Update sbuf */
463 sb->sb_cc -= nn;
464 sb->sb_rptr += nn;
465 if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
466 sb->sb_rptr -= sb->sb_datalen;
467
468 /*
469 * If in DRAIN mode, and there's no more data, set
470 * it CANTSENDMORE
471 */
472 if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
473 sofcantsendmore(so);
474
475 return nn;
476
477 err_disconnected:
478 DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d",
479 so->so_state, errno);
480 sofcantsendmore(so);
481 tcp_sockclosed(sototcpcb(so));
482 return -1;
483 }
484
485 /*
486 * recvfrom() a UDP socket
487 */
488 void sorecvfrom(struct socket *so)
489 {
490 struct sockaddr_storage addr;
491 struct sockaddr_storage saddr, daddr;
492 socklen_t addrlen = sizeof(struct sockaddr_storage);
493
494 DEBUG_CALL("sorecvfrom");
495 DEBUG_ARG("so = %p", so);
496
497 if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */
498 char buff[256];
499 int len;
500
501 len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen);
502 /* XXX Check if reply is "correct"? */
503
504 if (len == -1 || len == 0) {
505 uint8_t code = ICMP_UNREACH_PORT;
506
507 if (errno == EHOSTUNREACH)
508 code = ICMP_UNREACH_HOST;
509 else if (errno == ENETUNREACH)
510 code = ICMP_UNREACH_NET;
511
512 DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno));
513 icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
514 } else {
515 icmp_reflect(so->so_m);
516 so->so_m = NULL; /* Don't m_free() it again! */
517 }
518 /* No need for this socket anymore, udp_detach it */
519 udp_detach(so);
520 } else { /* A "normal" UDP packet */
521 struct mbuf *m;
522 int len;
523 #ifdef _WIN32
524 unsigned long n;
525 #else
526 int n;
527 #endif
528
529 if (ioctlsocket(so->s, FIONREAD, &n) != 0) {
530 DEBUG_MISC(" ioctlsocket errno = %d-%s\n", errno, strerror(errno));
531 return;
532 }
533 if (n == 0) {
534 return;
535 }
536
537 m = m_get(so->slirp);
538 if (!m) {
539 return;
540 }
541 switch (so->so_ffamily) {
542 case AF_INET:
543 m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
544 break;
545 case AF_INET6:
546 m->m_data +=
547 IF_MAXLINKHDR + sizeof(struct ip6) + sizeof(struct udphdr);
548 break;
549 default:
550 g_assert_not_reached();
551 break;
552 }
553
554 /*
555 * XXX Shouldn't FIONREAD packets destined for port 53,
556 * but I don't know the max packet size for DNS lookups
557 */
558 len = M_FREEROOM(m);
559 /* if (so->so_fport != htons(53)) { */
560
561 if (n > len) {
562 n = (m->m_data - m->m_dat) + m->m_len + n + 1;
563 m_inc(m, n);
564 len = M_FREEROOM(m);
565 }
566 /* } */
567
568 m->m_len = recvfrom(so->s, m->m_data, len, 0, (struct sockaddr *)&addr,
569 &addrlen);
570 DEBUG_MISC(" did recvfrom %d, errno = %d-%s", m->m_len, errno,
571 strerror(errno));
572 if (m->m_len < 0) {
573 /* Report error as ICMP */
574 switch (so->so_lfamily) {
575 uint8_t code;
576 case AF_INET:
577 code = ICMP_UNREACH_PORT;
578
579 if (errno == EHOSTUNREACH) {
580 code = ICMP_UNREACH_HOST;
581 } else if (errno == ENETUNREACH) {
582 code = ICMP_UNREACH_NET;
583 }
584
585 DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code);
586 icmp_send_error(so->so_m, ICMP_UNREACH, code, 0,
587 strerror(errno));
588 break;
589 case AF_INET6:
590 code = ICMP6_UNREACH_PORT;
591
592 if (errno == EHOSTUNREACH) {
593 code = ICMP6_UNREACH_ADDRESS;
594 } else if (errno == ENETUNREACH) {
595 code = ICMP6_UNREACH_NO_ROUTE;
596 }
597
598 DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code);
599 icmp6_send_error(so->so_m, ICMP6_UNREACH, code);
600 break;
601 default:
602 g_assert_not_reached();
603 break;
604 }
605 m_free(m);
606 } else {
607 /*
608 * Hack: domain name lookup will be used the most for UDP,
609 * and since they'll only be used once there's no need
610 * for the 4 minute (or whatever) timeout... So we time them
611 * out much quicker (10 seconds for now...)
612 */
613 if (so->so_expire) {
614 if (so->so_fport == htons(53))
615 so->so_expire = curtime + SO_EXPIREFAST;
616 else
617 so->so_expire = curtime + SO_EXPIRE;
618 }
619
620 /*
621 * If this packet was destined for CTL_ADDR,
622 * make it look like that's where it came from
623 */
624 saddr = addr;
625 sotranslate_in(so, &saddr);
626 daddr = so->lhost.ss;
627
628 switch (so->so_ffamily) {
629 case AF_INET:
630 udp_output(so, m, (struct sockaddr_in *)&saddr,
631 (struct sockaddr_in *)&daddr, so->so_iptos);
632 break;
633 case AF_INET6:
634 udp6_output(so, m, (struct sockaddr_in6 *)&saddr,
635 (struct sockaddr_in6 *)&daddr);
636 break;
637 default:
638 g_assert_not_reached();
639 break;
640 }
641 } /* rx error */
642 } /* if ping packet */
643 }
644
645 /*
646 * sendto() a socket
647 */
648 int sosendto(struct socket *so, struct mbuf *m)
649 {
650 int ret;
651 struct sockaddr_storage addr;
652
653 DEBUG_CALL("sosendto");
654 DEBUG_ARG("so = %p", so);
655 DEBUG_ARG("m = %p", m);
656
657 addr = so->fhost.ss;
658 DEBUG_CALL(" sendto()ing)");
659 if (sotranslate_out(so, &addr) < 0) {
660 return -1;
661 }
662
663 /* Don't care what port we get */
664 ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr,
665 sockaddr_size(&addr));
666 if (ret < 0)
667 return -1;
668
669 /*
670 * Kill the socket if there's no reply in 4 minutes,
671 * but only if it's an expirable socket
672 */
673 if (so->so_expire)
674 so->so_expire = curtime + SO_EXPIRE;
675 so->so_state &= SS_PERSISTENT_MASK;
676 so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */
677 return 0;
678 }
679
680 /*
681 * Listen for incoming TCP connections
682 */
683 struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
684 uint32_t laddr, unsigned lport, int flags)
685 {
686 /* TODO: IPv6 */
687 struct sockaddr_in addr;
688 struct socket *so;
689 int s, opt = 1;
690 socklen_t addrlen = sizeof(addr);
691 memset(&addr, 0, addrlen);
692
693 DEBUG_CALL("tcp_listen");
694 DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){ .s_addr = haddr }));
695 DEBUG_ARG("hport = %d", ntohs(hport));
696 DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){ .s_addr = laddr }));
697 DEBUG_ARG("lport = %d", ntohs(lport));
698 DEBUG_ARG("flags = %x", flags);
699
700 so = socreate(slirp);
701
702 /* Don't tcp_attach... we don't need so_snd nor so_rcv */
703 if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
704 g_free(so);
705 return NULL;
706 }
707 insque(so, &slirp->tcb);
708
709 /*
710 * SS_FACCEPTONCE sockets must time out.
711 */
712 if (flags & SS_FACCEPTONCE)
713 so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT * 2;
714
715 so->so_state &= SS_PERSISTENT_MASK;
716 so->so_state |= (SS_FACCEPTCONN | flags);
717 so->so_lfamily = AF_INET;
718 so->so_lport = lport; /* Kept in network format */
719 so->so_laddr.s_addr = laddr; /* Ditto */
720
721 addr.sin_family = AF_INET;
722 addr.sin_addr.s_addr = haddr;
723 addr.sin_port = hport;
724
725 if (((s = slirp_socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
726 (slirp_socket_set_fast_reuse(s) < 0) ||
727 (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) ||
728 (listen(s, 1) < 0)) {
729 int tmperrno = errno; /* Don't clobber the real reason we failed */
730
731 if (s >= 0) {
732 closesocket(s);
733 }
734 sofree(so);
735 /* Restore the real errno */
736 #ifdef _WIN32
737 WSASetLastError(tmperrno);
738 #else
739 errno = tmperrno;
740 #endif
741 return NULL;
742 }
743 setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
744 opt = 1;
745 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
746
747 getsockname(s, (struct sockaddr *)&addr, &addrlen);
748 so->so_ffamily = AF_INET;
749 so->so_fport = addr.sin_port;
750 if (addr.sin_addr.s_addr == 0 ||
751 addr.sin_addr.s_addr == loopback_addr.s_addr)
752 so->so_faddr = slirp->vhost_addr;
753 else
754 so->so_faddr = addr.sin_addr;
755
756 so->s = s;
757 return so;
758 }
759
760 /*
761 * Various session state calls
762 * XXX Should be #define's
763 * The socket state stuff needs work, these often get call 2 or 3
764 * times each when only 1 was needed
765 */
766 void soisfconnecting(struct socket *so)
767 {
768 so->so_state &= ~(SS_NOFDREF | SS_ISFCONNECTED | SS_FCANTRCVMORE |
769 SS_FCANTSENDMORE | SS_FWDRAIN);
770 so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
771 }
772
773 void soisfconnected(struct socket *so)
774 {
775 so->so_state &= ~(SS_ISFCONNECTING | SS_FWDRAIN | SS_NOFDREF);
776 so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
777 }
778
779 static void sofcantrcvmore(struct socket *so)
780 {
781 if ((so->so_state & SS_NOFDREF) == 0) {
782 shutdown(so->s, 0);
783 }
784 so->so_state &= ~(SS_ISFCONNECTING);
785 if (so->so_state & SS_FCANTSENDMORE) {
786 so->so_state &= SS_PERSISTENT_MASK;
787 so->so_state |= SS_NOFDREF; /* Don't select it */
788 } else {
789 so->so_state |= SS_FCANTRCVMORE;
790 }
791 }
792
793 static void sofcantsendmore(struct socket *so)
794 {
795 if ((so->so_state & SS_NOFDREF) == 0) {
796 shutdown(so->s, 1); /* send FIN to fhost */
797 }
798 so->so_state &= ~(SS_ISFCONNECTING);
799 if (so->so_state & SS_FCANTRCVMORE) {
800 so->so_state &= SS_PERSISTENT_MASK;
801 so->so_state |= SS_NOFDREF; /* as above */
802 } else {
803 so->so_state |= SS_FCANTSENDMORE;
804 }
805 }
806
807 /*
808 * Set write drain mode
809 * Set CANTSENDMORE once all data has been write()n
810 */
811 void sofwdrain(struct socket *so)
812 {
813 if (so->so_rcv.sb_cc)
814 so->so_state |= SS_FWDRAIN;
815 else
816 sofcantsendmore(so);
817 }
818
819 /*
820 * Translate addr in host addr when it is a virtual address
821 */
822 int sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
823 {
824 int rc = 0;
825 Slirp *slirp = so->slirp;
826 struct sockaddr_in *sin = (struct sockaddr_in *)addr;
827 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
828
829 switch (addr->ss_family) {
830 case AF_INET:
831 if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
832 slirp->vnetwork_addr.s_addr) {
833 /* It's an alias */
834 if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
835 if (get_dns_addr(&sin->sin_addr) >= 0) {
836 goto ret;
837 }
838 }
839 if (slirp->disable_host_loopback) {
840 rc = -1;
841 errno = EPERM;
842 goto ret;
843 } else {
844 sin->sin_addr = loopback_addr;
845 }
846 }
847 break;
848 case AF_INET6:
849 if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
850 slirp->vprefix_len)) {
851 if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
852 uint32_t scope_id;
853 if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) {
854 sin6->sin6_scope_id = scope_id;
855 goto ret;
856 }
857 }
858 if (slirp->disable_host_loopback) {
859 rc = -1;
860 errno = EPERM;
861 goto ret;
862 } else {
863 sin6->sin6_addr = in6addr_loopback;
864 }
865 }
866 break;
867
868 default:
869 break;
870 }
871 ret:
872 return rc;
873 }
874
875 void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
876 {
877 Slirp *slirp = so->slirp;
878 struct sockaddr_in *sin = (struct sockaddr_in *)addr;
879 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
880
881 switch (addr->ss_family) {
882 case AF_INET:
883 if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
884 slirp->vnetwork_addr.s_addr) {
885 uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
886
887 if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
888 sin->sin_addr = slirp->vhost_addr;
889 } else if (sin->sin_addr.s_addr == loopback_addr.s_addr ||
890 so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
891 sin->sin_addr = so->so_faddr;
892 }
893 }
894 break;
895
896 case AF_INET6:
897 if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
898 slirp->vprefix_len)) {
899 if (in6_equal(&sin6->sin6_addr, &in6addr_loopback) ||
900 !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) {
901 sin6->sin6_addr = so->so_faddr6;
902 }
903 }
904 break;
905
906 default:
907 break;
908 }
909 }
910
911 /*
912 * Translate connections from localhost to the real hostname
913 */
914 void sotranslate_accept(struct socket *so)
915 {
916 Slirp *slirp = so->slirp;
917
918 switch (so->so_ffamily) {
919 case AF_INET:
920 if (so->so_faddr.s_addr == INADDR_ANY ||
921 (so->so_faddr.s_addr & loopback_mask) ==
922 (loopback_addr.s_addr & loopback_mask)) {
923 so->so_faddr = slirp->vhost_addr;
924 }
925 break;
926
927 case AF_INET6:
928 if (in6_equal(&so->so_faddr6, &in6addr_any) ||
929 in6_equal(&so->so_faddr6, &in6addr_loopback)) {
930 so->so_faddr6 = slirp->vhost_addr6;
931 }
932 break;
933
934 default:
935 break;
936 }
937 }
938
939 void sodrop(struct socket *s, int num)
940 {
941 if (sbdrop(&s->so_snd, num)) {
942 s->slirp->cb->notify(s->slirp->opaque);
943 }
944 }
+0
-164
vendor/libslirp/src/socket.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 */
4
5 #ifndef SLIRP_SOCKET_H
6 #define SLIRP_SOCKET_H
7
8 #include "misc.h"
9
10 #define SO_EXPIRE 240000
11 #define SO_EXPIREFAST 10000
12
13 /*
14 * Our socket structure
15 */
16
17 union slirp_sockaddr {
18 struct sockaddr_storage ss;
19 struct sockaddr_in sin;
20 struct sockaddr_in6 sin6;
21 };
22
23 struct socket {
24 struct socket *so_next, *so_prev; /* For a linked list of sockets */
25
26 int s; /* The actual socket */
27 struct gfwd_list *guestfwd;
28
29 int pollfds_idx; /* GPollFD GArray index */
30
31 Slirp *slirp; /* managing slirp instance */
32
33 /* XXX union these with not-yet-used sbuf params */
34 struct mbuf *so_m; /* Pointer to the original SYN packet,
35 * for non-blocking connect()'s, and
36 * PING reply's */
37 struct tcpiphdr *so_ti; /* Pointer to the original ti within
38 * so_mconn, for non-blocking connections */
39 uint32_t so_urgc;
40 union slirp_sockaddr fhost; /* Foreign host */
41 #define so_faddr fhost.sin.sin_addr
42 #define so_fport fhost.sin.sin_port
43 #define so_faddr6 fhost.sin6.sin6_addr
44 #define so_fport6 fhost.sin6.sin6_port
45 #define so_ffamily fhost.ss.ss_family
46
47 union slirp_sockaddr lhost; /* Local host */
48 #define so_laddr lhost.sin.sin_addr
49 #define so_lport lhost.sin.sin_port
50 #define so_laddr6 lhost.sin6.sin6_addr
51 #define so_lport6 lhost.sin6.sin6_port
52 #define so_lfamily lhost.ss.ss_family
53
54 uint8_t so_iptos; /* Type of service */
55 uint8_t so_emu; /* Is the socket emulated? */
56
57 uint8_t so_type; /* Type of socket, UDP or TCP */
58 int32_t so_state; /* internal state flags SS_*, below */
59
60 struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
61 unsigned so_expire; /* When the socket will expire */
62
63 int so_queued; /* Number of packets queued from this socket */
64 int so_nqueued; /* Number of packets queued in a row
65 * Used to determine when to "downgrade" a session
66 * from fastq to batchq */
67
68 struct sbuf so_rcv; /* Receive buffer */
69 struct sbuf so_snd; /* Send buffer */
70 };
71
72
73 /*
74 * Socket state bits. (peer means the host on the Internet,
75 * local host means the host on the other end of the modem)
76 */
77 #define SS_NOFDREF 0x001 /* No fd reference */
78
79 #define SS_ISFCONNECTING \
80 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
81 #define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
82 #define SS_FCANTRCVMORE \
83 0x008 /* Socket can't receive more from peer (for half-closes) */
84 #define SS_FCANTSENDMORE \
85 0x010 /* Socket can't send more to peer (for half-closes) */
86 #define SS_FWDRAIN \
87 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
88
89 #define SS_CTL 0x080
90 #define SS_FACCEPTCONN \
91 0x100 /* Socket is accepting connections from a host on the internet */
92 #define SS_FACCEPTONCE \
93 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
94
95 #define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */
96 #define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
97 #define SS_INCOMING \
98 0x2000 /* Connection was initiated by a host on the internet */
99
100 static inline int sockaddr_equal(struct sockaddr_storage *a,
101 struct sockaddr_storage *b)
102 {
103 if (a->ss_family != b->ss_family) {
104 return 0;
105 }
106
107 switch (a->ss_family) {
108 case AF_INET: {
109 struct sockaddr_in *a4 = (struct sockaddr_in *)a;
110 struct sockaddr_in *b4 = (struct sockaddr_in *)b;
111 return a4->sin_addr.s_addr == b4->sin_addr.s_addr &&
112 a4->sin_port == b4->sin_port;
113 }
114 case AF_INET6: {
115 struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a;
116 struct sockaddr_in6 *b6 = (struct sockaddr_in6 *)b;
117 return (in6_equal(&a6->sin6_addr, &b6->sin6_addr) &&
118 a6->sin6_port == b6->sin6_port);
119 }
120 default:
121 g_assert_not_reached();
122 }
123
124 return 0;
125 }
126
127 static inline socklen_t sockaddr_size(struct sockaddr_storage *a)
128 {
129 switch (a->ss_family) {
130 case AF_INET:
131 return sizeof(struct sockaddr_in);
132 case AF_INET6:
133 return sizeof(struct sockaddr_in6);
134 default:
135 g_assert_not_reached();
136 }
137 }
138
139 struct socket *solookup(struct socket **, struct socket *,
140 struct sockaddr_storage *, struct sockaddr_storage *);
141 struct socket *socreate(Slirp *);
142 void sofree(struct socket *);
143 int soread(struct socket *);
144 int sorecvoob(struct socket *);
145 int sosendoob(struct socket *);
146 int sowrite(struct socket *);
147 void sorecvfrom(struct socket *);
148 int sosendto(struct socket *, struct mbuf *);
149 struct socket *tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
150 void soisfconnecting(register struct socket *);
151 void soisfconnected(register struct socket *);
152 void sofwdrain(struct socket *);
153 struct iovec; /* For win32 */
154 size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
155 int soreadbuf(struct socket *so, const char *buf, int size);
156
157 int sotranslate_out(struct socket *, struct sockaddr_storage *);
158 void sotranslate_in(struct socket *, struct sockaddr_storage *);
159 void sotranslate_accept(struct socket *);
160 void sodrop(struct socket *, int num);
161
162
163 #endif /* SLIRP_SOCKET_H */
+0
-381
vendor/libslirp/src/state.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * libslirp
3 *
4 * Copyright (c) 2004-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "slirp.h"
25 #include "vmstate.h"
26 #include "stream.h"
27
28 static int slirp_tcp_post_load(void *opaque, int version)
29 {
30 tcp_template((struct tcpcb *)opaque);
31
32 return 0;
33 }
34
35 static const VMStateDescription vmstate_slirp_tcp = {
36 .name = "slirp-tcp",
37 .version_id = 0,
38 .post_load = slirp_tcp_post_load,
39 .fields = (VMStateField[]){ VMSTATE_INT16(t_state, struct tcpcb),
40 VMSTATE_INT16_ARRAY(t_timer, struct tcpcb,
41 TCPT_NTIMERS),
42 VMSTATE_INT16(t_rxtshift, struct tcpcb),
43 VMSTATE_INT16(t_rxtcur, struct tcpcb),
44 VMSTATE_INT16(t_dupacks, struct tcpcb),
45 VMSTATE_UINT16(t_maxseg, struct tcpcb),
46 VMSTATE_UINT8(t_force, struct tcpcb),
47 VMSTATE_UINT16(t_flags, struct tcpcb),
48 VMSTATE_UINT32(snd_una, struct tcpcb),
49 VMSTATE_UINT32(snd_nxt, struct tcpcb),
50 VMSTATE_UINT32(snd_up, struct tcpcb),
51 VMSTATE_UINT32(snd_wl1, struct tcpcb),
52 VMSTATE_UINT32(snd_wl2, struct tcpcb),
53 VMSTATE_UINT32(iss, struct tcpcb),
54 VMSTATE_UINT32(snd_wnd, struct tcpcb),
55 VMSTATE_UINT32(rcv_wnd, struct tcpcb),
56 VMSTATE_UINT32(rcv_nxt, struct tcpcb),
57 VMSTATE_UINT32(rcv_up, struct tcpcb),
58 VMSTATE_UINT32(irs, struct tcpcb),
59 VMSTATE_UINT32(rcv_adv, struct tcpcb),
60 VMSTATE_UINT32(snd_max, struct tcpcb),
61 VMSTATE_UINT32(snd_cwnd, struct tcpcb),
62 VMSTATE_UINT32(snd_ssthresh, struct tcpcb),
63 VMSTATE_INT16(t_idle, struct tcpcb),
64 VMSTATE_INT16(t_rtt, struct tcpcb),
65 VMSTATE_UINT32(t_rtseq, struct tcpcb),
66 VMSTATE_INT16(t_srtt, struct tcpcb),
67 VMSTATE_INT16(t_rttvar, struct tcpcb),
68 VMSTATE_UINT16(t_rttmin, struct tcpcb),
69 VMSTATE_UINT32(max_sndwnd, struct tcpcb),
70 VMSTATE_UINT8(t_oobflags, struct tcpcb),
71 VMSTATE_UINT8(t_iobc, struct tcpcb),
72 VMSTATE_INT16(t_softerror, struct tcpcb),
73 VMSTATE_UINT8(snd_scale, struct tcpcb),
74 VMSTATE_UINT8(rcv_scale, struct tcpcb),
75 VMSTATE_UINT8(request_r_scale, struct tcpcb),
76 VMSTATE_UINT8(requested_s_scale, struct tcpcb),
77 VMSTATE_UINT32(ts_recent, struct tcpcb),
78 VMSTATE_UINT32(ts_recent_age, struct tcpcb),
79 VMSTATE_UINT32(last_ack_sent, struct tcpcb),
80 VMSTATE_END_OF_LIST() }
81 };
82
83 /* The sbuf has a pair of pointers that are migrated as offsets;
84 * we calculate the offsets and restore the pointers using
85 * pre_save/post_load on a tmp structure.
86 */
87 struct sbuf_tmp {
88 struct sbuf *parent;
89 uint32_t roff, woff;
90 };
91
92 static int sbuf_tmp_pre_save(void *opaque)
93 {
94 struct sbuf_tmp *tmp = opaque;
95 tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data;
96 tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data;
97
98 return 0;
99 }
100
101 static int sbuf_tmp_post_load(void *opaque, int version)
102 {
103 struct sbuf_tmp *tmp = opaque;
104 uint32_t requested_len = tmp->parent->sb_datalen;
105
106 /* Allocate the buffer space used by the field after the tmp */
107 sbreserve(tmp->parent, tmp->parent->sb_datalen);
108
109 if (tmp->parent->sb_datalen != requested_len) {
110 return -ENOMEM;
111 }
112 if (tmp->woff >= requested_len || tmp->roff >= requested_len) {
113 g_critical("invalid sbuf offsets r/w=%u/%u len=%u", tmp->roff,
114 tmp->woff, requested_len);
115 return -EINVAL;
116 }
117
118 tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
119 tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
120
121 return 0;
122 }
123
124
125 static const VMStateDescription vmstate_slirp_sbuf_tmp = {
126 .name = "slirp-sbuf-tmp",
127 .post_load = sbuf_tmp_post_load,
128 .pre_save = sbuf_tmp_pre_save,
129 .version_id = 0,
130 .fields = (VMStateField[]){ VMSTATE_UINT32(woff, struct sbuf_tmp),
131 VMSTATE_UINT32(roff, struct sbuf_tmp),
132 VMSTATE_END_OF_LIST() }
133 };
134
135 static const VMStateDescription vmstate_slirp_sbuf = {
136 .name = "slirp-sbuf",
137 .version_id = 0,
138 .fields = (VMStateField[]){ VMSTATE_UINT32(sb_cc, struct sbuf),
139 VMSTATE_UINT32(sb_datalen, struct sbuf),
140 VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp,
141 vmstate_slirp_sbuf_tmp),
142 VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0,
143 NULL, sb_datalen),
144 VMSTATE_END_OF_LIST() }
145 };
146
147 static bool slirp_older_than_v4(void *opaque, int version_id)
148 {
149 return version_id < 4;
150 }
151
152 static bool slirp_family_inet(void *opaque, int version_id)
153 {
154 union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
155 return ssa->ss.ss_family == AF_INET;
156 }
157
158 static int slirp_socket_pre_load(void *opaque)
159 {
160 struct socket *so = opaque;
161 if (tcp_attach(so) < 0) {
162 return -ENOMEM;
163 }
164 /* Older versions don't load these fields */
165 so->so_ffamily = AF_INET;
166 so->so_lfamily = AF_INET;
167 return 0;
168 }
169
170 #ifndef _WIN32
171 #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
172 #else
173 /* Win uses u_long rather than uint32_t - but it's still 32bits long */
174 #define VMSTATE_SIN4_ADDR(f, s, t) \
175 VMSTATE_SINGLE_TEST(f, s, t, 0, slirp_vmstate_info_uint32, u_long)
176 #endif
177
178 /* The OS provided ss_family field isn't that portable; it's size
179 * and type varies (16/8 bit, signed, unsigned)
180 * and the values it contains aren't fully portable.
181 */
182 typedef struct SS_FamilyTmpStruct {
183 union slirp_sockaddr *parent;
184 uint16_t portable_family;
185 } SS_FamilyTmpStruct;
186
187 #define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */
188 #define SS_FAMILY_MIG_IPV6 10 /* Linux */
189 #define SS_FAMILY_MIG_OTHER 0xffff
190
191 static int ss_family_pre_save(void *opaque)
192 {
193 SS_FamilyTmpStruct *tss = opaque;
194
195 tss->portable_family = SS_FAMILY_MIG_OTHER;
196
197 if (tss->parent->ss.ss_family == AF_INET) {
198 tss->portable_family = SS_FAMILY_MIG_IPV4;
199 } else if (tss->parent->ss.ss_family == AF_INET6) {
200 tss->portable_family = SS_FAMILY_MIG_IPV6;
201 }
202
203 return 0;
204 }
205
206 static int ss_family_post_load(void *opaque, int version_id)
207 {
208 SS_FamilyTmpStruct *tss = opaque;
209
210 switch (tss->portable_family) {
211 case SS_FAMILY_MIG_IPV4:
212 tss->parent->ss.ss_family = AF_INET;
213 break;
214 case SS_FAMILY_MIG_IPV6:
215 case 23: /* compatibility: AF_INET6 from mingw */
216 case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
217 tss->parent->ss.ss_family = AF_INET6;
218 break;
219 default:
220 g_critical("invalid ss_family type %x", tss->portable_family);
221 return -EINVAL;
222 }
223
224 return 0;
225 }
226
227 static const VMStateDescription vmstate_slirp_ss_family = {
228 .name = "slirp-socket-addr/ss_family",
229 .pre_save = ss_family_pre_save,
230 .post_load = ss_family_post_load,
231 .fields =
232 (VMStateField[]){ VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
233 VMSTATE_END_OF_LIST() }
234 };
235
236 static const VMStateDescription vmstate_slirp_socket_addr = {
237 .name = "slirp-socket-addr",
238 .version_id = 4,
239 .fields =
240 (VMStateField[]){
241 VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct,
242 vmstate_slirp_ss_family),
243 VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr,
244 slirp_family_inet),
245 VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
246 slirp_family_inet),
247
248 #if 0
249 /* Untested: Needs checking by someone with IPv6 test */
250 VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
251 slirp_family_inet6),
252 VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
253 slirp_family_inet6),
254 VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
255 slirp_family_inet6),
256 VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
257 slirp_family_inet6),
258 #endif
259
260 VMSTATE_END_OF_LIST() }
261 };
262
263 static const VMStateDescription vmstate_slirp_socket = {
264 .name = "slirp-socket",
265 .version_id = 4,
266 .pre_load = slirp_socket_pre_load,
267 .fields =
268 (VMStateField[]){
269 VMSTATE_UINT32(so_urgc, struct socket),
270 /* Pre-v4 versions */
271 VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket,
272 slirp_older_than_v4),
273 VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket,
274 slirp_older_than_v4),
275 VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4),
276 VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4),
277 /* v4 and newer */
278 VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr,
279 union slirp_sockaddr),
280 VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr,
281 union slirp_sockaddr),
282
283 VMSTATE_UINT8(so_iptos, struct socket),
284 VMSTATE_UINT8(so_emu, struct socket),
285 VMSTATE_UINT8(so_type, struct socket),
286 VMSTATE_INT32(so_state, struct socket),
287 VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf,
288 struct sbuf),
289 VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
290 struct sbuf),
291 VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
292 struct tcpcb),
293 VMSTATE_END_OF_LIST() }
294 };
295
296 static const VMStateDescription vmstate_slirp_bootp_client = {
297 .name = "slirp_bootpclient",
298 .fields = (VMStateField[]){ VMSTATE_UINT16(allocated, BOOTPClient),
299 VMSTATE_BUFFER(macaddr, BOOTPClient),
300 VMSTATE_END_OF_LIST() }
301 };
302
303 static const VMStateDescription vmstate_slirp = {
304 .name = "slirp",
305 .version_id = 4,
306 .fields = (VMStateField[]){ VMSTATE_UINT16_V(ip_id, Slirp, 2),
307 VMSTATE_STRUCT_ARRAY(
308 bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3,
309 vmstate_slirp_bootp_client, BOOTPClient),
310 VMSTATE_END_OF_LIST() }
311 };
312
313 void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque)
314 {
315 struct gfwd_list *ex_ptr;
316 SlirpOStream f = {
317 .write_cb = write_cb,
318 .opaque = opaque,
319 };
320
321 for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
322 if (ex_ptr->write_cb) {
323 struct socket *so;
324 so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
325 ntohs(ex_ptr->ex_fport));
326 if (!so) {
327 continue;
328 }
329
330 slirp_ostream_write_u8(&f, 42);
331 slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so);
332 }
333 slirp_ostream_write_u8(&f, 0);
334
335 slirp_vmstate_save_state(&f, &vmstate_slirp, slirp);
336 }
337
338
339 int slirp_state_load(Slirp *slirp, int version_id, SlirpReadCb read_cb,
340 void *opaque)
341 {
342 struct gfwd_list *ex_ptr;
343 SlirpIStream f = {
344 .read_cb = read_cb,
345 .opaque = opaque,
346 };
347
348 while (slirp_istream_read_u8(&f)) {
349 int ret;
350 struct socket *so = socreate(slirp);
351
352 ret =
353 slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id);
354 if (ret < 0) {
355 return ret;
356 }
357
358 if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
359 slirp->vnetwork_addr.s_addr) {
360 return -EINVAL;
361 }
362 for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
363 if (ex_ptr->write_cb &&
364 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
365 so->so_fport == ex_ptr->ex_fport) {
366 break;
367 }
368 }
369 if (!ex_ptr) {
370 return -EINVAL;
371 }
372 }
373
374 return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id);
375 }
376
377 int slirp_state_version(void)
378 {
379 return 4;
380 }
+0
-120
vendor/libslirp/src/stream.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * libslirp io streams
3 *
4 * Copyright (c) 2018 Red Hat, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "stream.h"
25 #include <glib.h>
26
27 bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size)
28 {
29 return f->read_cb(buf, size, f->opaque) == size;
30 }
31
32 bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size)
33 {
34 return f->write_cb(buf, size, f->opaque) == size;
35 }
36
37 uint8_t slirp_istream_read_u8(SlirpIStream *f)
38 {
39 uint8_t b;
40
41 if (slirp_istream_read(f, &b, sizeof(b))) {
42 return b;
43 }
44
45 return 0;
46 }
47
48 bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b)
49 {
50 return slirp_ostream_write(f, &b, sizeof(b));
51 }
52
53 uint16_t slirp_istream_read_u16(SlirpIStream *f)
54 {
55 uint16_t b;
56
57 if (slirp_istream_read(f, &b, sizeof(b))) {
58 return GUINT16_FROM_BE(b);
59 }
60
61 return 0;
62 }
63
64 bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b)
65 {
66 b = GUINT16_TO_BE(b);
67 return slirp_ostream_write(f, &b, sizeof(b));
68 }
69
70 uint32_t slirp_istream_read_u32(SlirpIStream *f)
71 {
72 uint32_t b;
73
74 if (slirp_istream_read(f, &b, sizeof(b))) {
75 return GUINT32_FROM_BE(b);
76 }
77
78 return 0;
79 }
80
81 bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b)
82 {
83 b = GUINT32_TO_BE(b);
84 return slirp_ostream_write(f, &b, sizeof(b));
85 }
86
87 int16_t slirp_istream_read_i16(SlirpIStream *f)
88 {
89 int16_t b;
90
91 if (slirp_istream_read(f, &b, sizeof(b))) {
92 return GINT16_FROM_BE(b);
93 }
94
95 return 0;
96 }
97
98 bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b)
99 {
100 b = GINT16_TO_BE(b);
101 return slirp_ostream_write(f, &b, sizeof(b));
102 }
103
104 int32_t slirp_istream_read_i32(SlirpIStream *f)
105 {
106 int32_t b;
107
108 if (slirp_istream_read(f, &b, sizeof(b))) {
109 return GINT32_FROM_BE(b);
110 }
111
112 return 0;
113 }
114
115 bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b)
116 {
117 b = GINT32_TO_BE(b);
118 return slirp_ostream_write(f, &b, sizeof(b));
119 }
+0
-35
vendor/libslirp/src/stream.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 #ifndef STREAM_H_
2 #define STREAM_H_
3
4 #include "libslirp.h"
5
6 typedef struct SlirpIStream {
7 SlirpReadCb read_cb;
8 void *opaque;
9 } SlirpIStream;
10
11 typedef struct SlirpOStream {
12 SlirpWriteCb write_cb;
13 void *opaque;
14 } SlirpOStream;
15
16 bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size);
17 bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size);
18
19 uint8_t slirp_istream_read_u8(SlirpIStream *f);
20 bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b);
21
22 uint16_t slirp_istream_read_u16(SlirpIStream *f);
23 bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b);
24
25 uint32_t slirp_istream_read_u32(SlirpIStream *f);
26 bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b);
27
28 int16_t slirp_istream_read_i16(SlirpIStream *f);
29 bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b);
30
31 int32_t slirp_istream_read_i32(SlirpIStream *f);
32 bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b);
33
34 #endif /* STREAM_H_ */
+0
-169
vendor/libslirp/src/tcp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp.h 8.1 (Berkeley) 6/10/93
30 * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp
31 */
32
33 #ifndef TCP_H
34 #define TCP_H
35
36 #include <glib.h>
37
38 typedef uint32_t tcp_seq;
39
40 #define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
41 #define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
42
43 #define TCP_SNDSPACE 1024 * 128
44 #define TCP_RCVSPACE 1024 * 128
45 #define TCP_MAXSEG_MAX 32768
46
47 /*
48 * TCP header.
49 * Per RFC 793, September, 1981.
50 */
51 #define tcphdr slirp_tcphdr
52 struct tcphdr {
53 uint16_t th_sport; /* source port */
54 uint16_t th_dport; /* destination port */
55 tcp_seq th_seq; /* sequence number */
56 tcp_seq th_ack; /* acknowledgement number */
57 #if G_BYTE_ORDER == G_BIG_ENDIAN
58 uint8_t th_off : 4, /* data offset */
59 th_x2 : 4; /* (unused) */
60 #else
61 uint8_t th_x2 : 4, /* (unused) */
62 th_off : 4; /* data offset */
63 #endif
64 uint8_t th_flags;
65 uint16_t th_win; /* window */
66 uint16_t th_sum; /* checksum */
67 uint16_t th_urp; /* urgent pointer */
68 };
69
70 #include "tcp_var.h"
71
72 #ifndef TH_FIN
73 #define TH_FIN 0x01
74 #define TH_SYN 0x02
75 #define TH_RST 0x04
76 #define TH_PUSH 0x08
77 #define TH_ACK 0x10
78 #define TH_URG 0x20
79 #endif
80
81 #ifndef TCPOPT_EOL
82 #define TCPOPT_EOL 0
83 #define TCPOPT_NOP 1
84 #define TCPOPT_MAXSEG 2
85 #define TCPOPT_WINDOW 3
86 #define TCPOPT_SACK_PERMITTED 4 /* Experimental */
87 #define TCPOPT_SACK 5 /* Experimental */
88 #define TCPOPT_TIMESTAMP 8
89
90 #define TCPOPT_TSTAMP_HDR \
91 (TCPOPT_NOP << 24 | TCPOPT_NOP << 16 | TCPOPT_TIMESTAMP << 8 | \
92 TCPOLEN_TIMESTAMP)
93 #endif
94
95 #ifndef TCPOLEN_MAXSEG
96 #define TCPOLEN_MAXSEG 4
97 #define TCPOLEN_WINDOW 3
98 #define TCPOLEN_SACK_PERMITTED 2
99 #define TCPOLEN_TIMESTAMP 10
100 #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP + 2) /* appendix A */
101 #endif
102
103 #undef TCP_MAXWIN
104 #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
105
106 #undef TCP_MAX_WINSHIFT
107 #define TCP_MAX_WINSHIFT 14 /* maximum window shift */
108
109 /*
110 * User-settable options (used with setsockopt).
111 *
112 * We don't use the system headers on unix because we have conflicting
113 * local structures. We can't avoid the system definitions on Windows,
114 * so we undefine them.
115 */
116 #undef TCP_NODELAY
117 #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
118 #undef TCP_MAXSEG
119
120 /*
121 * TCP FSM state definitions.
122 * Per RFC793, September, 1981.
123 */
124
125 #define TCP_NSTATES 11
126
127 #define TCPS_CLOSED 0 /* closed */
128 #define TCPS_LISTEN 1 /* listening for connection */
129 #define TCPS_SYN_SENT 2 /* active, have sent syn */
130 #define TCPS_SYN_RECEIVED 3 /* have send and received syn */
131 /* states < TCPS_ESTABLISHED are those where connections not established */
132 #define TCPS_ESTABLISHED 4 /* established */
133 #define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */
134 /* states > TCPS_CLOSE_WAIT are those where user has closed */
135 #define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */
136 #define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */
137 #define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */
138 /* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
139 #define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */
140 #define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
141
142 #define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED)
143 #define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
144 #define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT)
145
146 /*
147 * TCP sequence numbers are 32 bit integers operated
148 * on with modular arithmetic. These macros can be
149 * used to compare such integers.
150 */
151 #define SEQ_LT(a, b) ((int)((a) - (b)) < 0)
152 #define SEQ_LEQ(a, b) ((int)((a) - (b)) <= 0)
153 #define SEQ_GT(a, b) ((int)((a) - (b)) > 0)
154 #define SEQ_GEQ(a, b) ((int)((a) - (b)) >= 0)
155
156 /*
157 * Macros to initialize tcp sequence numbers for
158 * send and receive from initial send and receive
159 * sequence numbers.
160 */
161 #define tcp_rcvseqinit(tp) (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
162
163 #define tcp_sendseqinit(tp) \
164 (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss
165
166 #define TCP_ISSINCR (125 * 1024) /* increment for tcp_iss each second */
167
168 #endif
+0
-1542
vendor/libslirp/src/tcp_input.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94
30 * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP
35 * Copyright (c) 1995 Danny Gasparovski.
36 */
37
38 #include "slirp.h"
39 #include "ip_icmp.h"
40
41 #define TCPREXMTTHRESH 3
42
43 #define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ)
44
45 /* for modulo comparisons of timestamps */
46 #define TSTMP_LT(a, b) ((int)((a) - (b)) < 0)
47 #define TSTMP_GEQ(a, b) ((int)((a) - (b)) >= 0)
48
49 /*
50 * Insert segment ti into reassembly queue of tcp with
51 * control block tp. Return TH_FIN if reassembly now includes
52 * a segment with FIN. The macro form does the common case inline
53 * (segment is the next to be received on an established connection,
54 * and the queue is empty), avoiding linkage into and removal
55 * from the queue and repetition of various conversions.
56 * Set DELACK for segments received in order, but ack immediately
57 * when segments are out of order (so fast retransmit can work).
58 */
59 #define TCP_REASS(tp, ti, m, so, flags) \
60 { \
61 if ((ti)->ti_seq == (tp)->rcv_nxt && tcpfrag_list_empty(tp) && \
62 (tp)->t_state == TCPS_ESTABLISHED) { \
63 tp->t_flags |= TF_DELACK; \
64 (tp)->rcv_nxt += (ti)->ti_len; \
65 flags = (ti)->ti_flags & TH_FIN; \
66 if (so->so_emu) { \
67 if (tcp_emu((so), (m))) \
68 sbappend(so, (m)); \
69 } else \
70 sbappend((so), (m)); \
71 } else { \
72 (flags) = tcp_reass((tp), (ti), (m)); \
73 tp->t_flags |= TF_ACKNOW; \
74 } \
75 }
76
77 static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt,
78 struct tcpiphdr *ti);
79 static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
80
81 static int tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
82 struct mbuf *m)
83 {
84 register struct tcpiphdr *q;
85 struct socket *so = tp->t_socket;
86 int flags;
87
88 /*
89 * Call with ti==NULL after become established to
90 * force pre-ESTABLISHED data up to user socket.
91 */
92 if (ti == NULL)
93 goto present;
94
95 /*
96 * Find a segment which begins after this one does.
97 */
98 for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
99 q = tcpiphdr_next(q))
100 if (SEQ_GT(q->ti_seq, ti->ti_seq))
101 break;
102
103 /*
104 * If there is a preceding segment, it may provide some of
105 * our data already. If so, drop the data from the incoming
106 * segment. If it provides all of our data, drop us.
107 */
108 if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) {
109 register int i;
110 q = tcpiphdr_prev(q);
111 /* conversion to int (in i) handles seq wraparound */
112 i = q->ti_seq + q->ti_len - ti->ti_seq;
113 if (i > 0) {
114 if (i >= ti->ti_len) {
115 m_free(m);
116 /*
117 * Try to present any queued data
118 * at the left window edge to the user.
119 * This is needed after the 3-WHS
120 * completes.
121 */
122 goto present; /* ??? */
123 }
124 m_adj(m, i);
125 ti->ti_len -= i;
126 ti->ti_seq += i;
127 }
128 q = tcpiphdr_next(q);
129 }
130 ti->ti_mbuf = m;
131
132 /*
133 * While we overlap succeeding segments trim them or,
134 * if they are completely covered, dequeue them.
135 */
136 while (!tcpfrag_list_end(q, tp)) {
137 register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
138 if (i <= 0)
139 break;
140 if (i < q->ti_len) {
141 q->ti_seq += i;
142 q->ti_len -= i;
143 m_adj(q->ti_mbuf, i);
144 break;
145 }
146 q = tcpiphdr_next(q);
147 m = tcpiphdr_prev(q)->ti_mbuf;
148 remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
149 m_free(m);
150 }
151
152 /*
153 * Stick new segment in its place.
154 */
155 insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q)));
156
157 present:
158 /*
159 * Present data to user, advancing rcv_nxt through
160 * completed sequence space.
161 */
162 if (!TCPS_HAVEESTABLISHED(tp->t_state))
163 return (0);
164 ti = tcpfrag_list_first(tp);
165 if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
166 return (0);
167 if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
168 return (0);
169 do {
170 tp->rcv_nxt += ti->ti_len;
171 flags = ti->ti_flags & TH_FIN;
172 remque(tcpiphdr2qlink(ti));
173 m = ti->ti_mbuf;
174 ti = tcpiphdr_next(ti);
175 if (so->so_state & SS_FCANTSENDMORE)
176 m_free(m);
177 else {
178 if (so->so_emu) {
179 if (tcp_emu(so, m))
180 sbappend(so, m);
181 } else
182 sbappend(so, m);
183 }
184 } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
185 return (flags);
186 }
187
188 /*
189 * TCP input routine, follows pages 65-76 of the
190 * protocol specification dated September, 1981 very closely.
191 */
192 void tcp_input(struct mbuf *m, int iphlen, struct socket *inso,
193 unsigned short af)
194 {
195 struct ip save_ip, *ip;
196 struct ip6 save_ip6, *ip6;
197 register struct tcpiphdr *ti;
198 char *optp = NULL;
199 int optlen = 0;
200 int len, tlen, off;
201 register struct tcpcb *tp = NULL;
202 register int tiflags;
203 struct socket *so = NULL;
204 int todrop, acked, ourfinisacked, needoutput = 0;
205 int iss = 0;
206 uint32_t tiwin;
207 int ret;
208 struct sockaddr_storage lhost, fhost;
209 struct sockaddr_in *lhost4, *fhost4;
210 struct sockaddr_in6 *lhost6, *fhost6;
211 struct gfwd_list *ex_ptr;
212 Slirp *slirp;
213
214 DEBUG_CALL("tcp_input");
215 DEBUG_ARG("m = %p iphlen = %2d inso = %p", m, iphlen, inso);
216
217 /*
218 * If called with m == 0, then we're continuing the connect
219 */
220 if (m == NULL) {
221 so = inso;
222 slirp = so->slirp;
223
224 /* Re-set a few variables */
225 tp = sototcpcb(so);
226 m = so->so_m;
227 so->so_m = NULL;
228 ti = so->so_ti;
229 tiwin = ti->ti_win;
230 tiflags = ti->ti_flags;
231
232 goto cont_conn;
233 }
234 slirp = m->slirp;
235
236 ip = mtod(m, struct ip *);
237 ip6 = mtod(m, struct ip6 *);
238
239 switch (af) {
240 case AF_INET:
241 if (iphlen > sizeof(struct ip)) {
242 ip_stripoptions(m, (struct mbuf *)0);
243 iphlen = sizeof(struct ip);
244 }
245 /* XXX Check if too short */
246
247
248 /*
249 * Save a copy of the IP header in case we want restore it
250 * for sending an ICMP error message in response.
251 */
252 save_ip = *ip;
253 save_ip.ip_len += iphlen;
254
255 /*
256 * Get IP and TCP header together in first mbuf.
257 * Note: IP leaves IP header in first mbuf.
258 */
259 m->m_data -=
260 sizeof(struct tcpiphdr) - sizeof(struct ip) - sizeof(struct tcphdr);
261 m->m_len +=
262 sizeof(struct tcpiphdr) - sizeof(struct ip) - sizeof(struct tcphdr);
263 ti = mtod(m, struct tcpiphdr *);
264
265 /*
266 * Checksum extended TCP header and data.
267 */
268 tlen = ip->ip_len;
269 tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
270 memset(&ti->ih_mbuf, 0, sizeof(struct mbuf_ptr));
271 memset(&ti->ti, 0, sizeof(ti->ti));
272 ti->ti_x0 = 0;
273 ti->ti_src = save_ip.ip_src;
274 ti->ti_dst = save_ip.ip_dst;
275 ti->ti_pr = save_ip.ip_p;
276 ti->ti_len = htons((uint16_t)tlen);
277 break;
278
279 case AF_INET6:
280 /*
281 * Save a copy of the IP header in case we want restore it
282 * for sending an ICMP error message in response.
283 */
284 save_ip6 = *ip6;
285 /*
286 * Get IP and TCP header together in first mbuf.
287 * Note: IP leaves IP header in first mbuf.
288 */
289 m->m_data -= sizeof(struct tcpiphdr) -
290 (sizeof(struct ip6) + sizeof(struct tcphdr));
291 m->m_len += sizeof(struct tcpiphdr) -
292 (sizeof(struct ip6) + sizeof(struct tcphdr));
293 ti = mtod(m, struct tcpiphdr *);
294
295 tlen = ip6->ip_pl;
296 tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
297 memset(&ti->ih_mbuf, 0, sizeof(struct mbuf_ptr));
298 memset(&ti->ti, 0, sizeof(ti->ti));
299 ti->ti_x0 = 0;
300 ti->ti_src6 = save_ip6.ip_src;
301 ti->ti_dst6 = save_ip6.ip_dst;
302 ti->ti_nh6 = save_ip6.ip_nh;
303 ti->ti_len = htons((uint16_t)tlen);
304 break;
305
306 default:
307 g_assert_not_reached();
308 }
309
310 len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
311 if (cksum(m, len)) {
312 goto drop;
313 }
314
315 /*
316 * Check that TCP offset makes sense,
317 * pull out TCP options and adjust length. XXX
318 */
319 off = ti->ti_off << 2;
320 if (off < sizeof(struct tcphdr) || off > tlen) {
321 goto drop;
322 }
323 tlen -= off;
324 ti->ti_len = tlen;
325 if (off > sizeof(struct tcphdr)) {
326 optlen = off - sizeof(struct tcphdr);
327 optp = mtod(m, char *) + sizeof(struct tcpiphdr);
328 }
329 tiflags = ti->ti_flags;
330
331 /*
332 * Convert TCP protocol specific fields to host format.
333 */
334 NTOHL(ti->ti_seq);
335 NTOHL(ti->ti_ack);
336 NTOHS(ti->ti_win);
337 NTOHS(ti->ti_urp);
338
339 /*
340 * Drop TCP, IP headers and TCP options.
341 */
342 m->m_data += sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);
343 m->m_len -= sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);
344
345 /*
346 * Locate pcb for segment.
347 */
348 findso:
349 lhost.ss_family = af;
350 fhost.ss_family = af;
351 switch (af) {
352 case AF_INET:
353 lhost4 = (struct sockaddr_in *)&lhost;
354 lhost4->sin_addr = ti->ti_src;
355 lhost4->sin_port = ti->ti_sport;
356 fhost4 = (struct sockaddr_in *)&fhost;
357 fhost4->sin_addr = ti->ti_dst;
358 fhost4->sin_port = ti->ti_dport;
359 break;
360 case AF_INET6:
361 lhost6 = (struct sockaddr_in6 *)&lhost;
362 lhost6->sin6_addr = ti->ti_src6;
363 lhost6->sin6_port = ti->ti_sport;
364 fhost6 = (struct sockaddr_in6 *)&fhost;
365 fhost6->sin6_addr = ti->ti_dst6;
366 fhost6->sin6_port = ti->ti_dport;
367 break;
368 default:
369 g_assert_not_reached();
370 }
371
372 so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
373
374 /*
375 * If the state is CLOSED (i.e., TCB does not exist) then
376 * all data in the incoming segment is discarded.
377 * If the TCB exists but is in CLOSED state, it is embryonic,
378 * but should either do a listen or a connect soon.
379 *
380 * state == CLOSED means we've done socreate() but haven't
381 * attached it to a protocol yet...
382 *
383 * XXX If a TCB does not exist, and the TH_SYN flag is
384 * the only flag set, then create a session, mark it
385 * as if it was LISTENING, and continue...
386 */
387 if (so == NULL) {
388 /* TODO: IPv6 */
389 if (slirp->restricted) {
390 /* Any hostfwds will have an existing socket, so we only get here
391 * for non-hostfwd connections. These should be dropped, unless it
392 * happens to be a guestfwd.
393 */
394 for (ex_ptr = slirp->guestfwd_list; ex_ptr;
395 ex_ptr = ex_ptr->ex_next) {
396 if (ex_ptr->ex_fport == ti->ti_dport &&
397 ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
398 break;
399 }
400 }
401 if (!ex_ptr) {
402 goto dropwithreset;
403 }
404 }
405
406 if ((tiflags & (TH_SYN | TH_FIN | TH_RST | TH_URG | TH_ACK)) != TH_SYN)
407 goto dropwithreset;
408
409 so = socreate(slirp);
410 if (tcp_attach(so) < 0) {
411 g_free(so); /* Not sofree (if it failed, it's not insqued) */
412 goto dropwithreset;
413 }
414
415 sbreserve(&so->so_snd, TCP_SNDSPACE);
416 sbreserve(&so->so_rcv, TCP_RCVSPACE);
417
418 so->lhost.ss = lhost;
419 so->fhost.ss = fhost;
420
421 so->so_iptos = tcp_tos(so);
422 if (so->so_iptos == 0) {
423 switch (af) {
424 case AF_INET:
425 so->so_iptos = ((struct ip *)ti)->ip_tos;
426 break;
427 case AF_INET6:
428 break;
429 default:
430 g_assert_not_reached();
431 }
432 }
433
434 tp = sototcpcb(so);
435 tp->t_state = TCPS_LISTEN;
436 }
437
438 /*
439 * If this is a still-connecting socket, this probably
440 * a retransmit of the SYN. Whether it's a retransmit SYN
441 * or something else, we nuke it.
442 */
443 if (so->so_state & SS_ISFCONNECTING)
444 goto drop;
445
446 tp = sototcpcb(so);
447
448 /* XXX Should never fail */
449 if (tp == NULL)
450 goto dropwithreset;
451 if (tp->t_state == TCPS_CLOSED)
452 goto drop;
453
454 tiwin = ti->ti_win;
455
456 /*
457 * Segment received on connection.
458 * Reset idle time and keep-alive timer.
459 */
460 tp->t_idle = 0;
461 if (slirp_do_keepalive)
462 tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
463 else
464 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
465
466 /*
467 * Process options if not in LISTEN state,
468 * else do it below (after getting remote address).
469 */
470 if (optp && tp->t_state != TCPS_LISTEN)
471 tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
472
473 /*
474 * Header prediction: check for the two common cases
475 * of a uni-directional data xfer. If the packet has
476 * no control flags, is in-sequence, the window didn't
477 * change and we're not retransmitting, it's a
478 * candidate. If the length is zero and the ack moved
479 * forward, we're the sender side of the xfer. Just
480 * free the data acked & wake any higher level process
481 * that was blocked waiting for space. If the length
482 * is non-zero and the ack didn't move, we're the
483 * receiver side. If we're getting packets in-order
484 * (the reassembly queue is empty), add the data to
485 * the socket buffer and note that we need a delayed ack.
486 *
487 * XXX Some of these tests are not needed
488 * eg: the tiwin == tp->snd_wnd prevents many more
489 * predictions.. with no *real* advantage..
490 */
491 if (tp->t_state == TCPS_ESTABLISHED &&
492 (tiflags & (TH_SYN | TH_FIN | TH_RST | TH_URG | TH_ACK)) == TH_ACK &&
493 ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd &&
494 tp->snd_nxt == tp->snd_max) {
495 if (ti->ti_len == 0) {
496 if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
497 SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
498 tp->snd_cwnd >= tp->snd_wnd) {
499 /*
500 * this is a pure ack for outstanding data.
501 */
502 if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
503 tcp_xmit_timer(tp, tp->t_rtt);
504 acked = ti->ti_ack - tp->snd_una;
505 sodrop(so, acked);
506 tp->snd_una = ti->ti_ack;
507 m_free(m);
508
509 /*
510 * If all outstanding data are acked, stop
511 * retransmit timer, otherwise restart timer
512 * using current (possibly backed-off) value.
513 * If process is waiting for space,
514 * wakeup/selwakeup/signal. If data
515 * are ready to send, let tcp_output
516 * decide between more output or persist.
517 */
518 if (tp->snd_una == tp->snd_max)
519 tp->t_timer[TCPT_REXMT] = 0;
520 else if (tp->t_timer[TCPT_PERSIST] == 0)
521 tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
522
523 /*
524 * This is called because sowwakeup might have
525 * put data into so_snd. Since we don't so sowwakeup,
526 * we don't need this.. XXX???
527 */
528 if (so->so_snd.sb_cc)
529 (void)tcp_output(tp);
530
531 return;
532 }
533 } else if (ti->ti_ack == tp->snd_una && tcpfrag_list_empty(tp) &&
534 ti->ti_len <= sbspace(&so->so_rcv)) {
535 /*
536 * this is a pure, in-sequence data packet
537 * with nothing on the reassembly queue and
538 * we have enough buffer space to take it.
539 */
540 tp->rcv_nxt += ti->ti_len;
541 /*
542 * Add data to socket buffer.
543 */
544 if (so->so_emu) {
545 if (tcp_emu(so, m))
546 sbappend(so, m);
547 } else
548 sbappend(so, m);
549
550 /*
551 * If this is a short packet, then ACK now - with Nagel
552 * congestion avoidance sender won't send more until
553 * he gets an ACK.
554 *
555 * It is better to not delay acks at all to maximize
556 * TCP throughput. See RFC 2581.
557 */
558 tp->t_flags |= TF_ACKNOW;
559 tcp_output(tp);
560 return;
561 }
562 } /* header prediction */
563 /*
564 * Calculate amount of space in receive window,
565 * and then do TCP input processing.
566 * Receive window is amount of space in rcv queue,
567 * but not less than advertised window.
568 */
569 {
570 int win;
571 win = sbspace(&so->so_rcv);
572 if (win < 0)
573 win = 0;
574 tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt));
575 }
576
577 switch (tp->t_state) {
578 /*
579 * If the state is LISTEN then ignore segment if it contains an RST.
580 * If the segment contains an ACK then it is bad and send a RST.
581 * If it does not contain a SYN then it is not interesting; drop it.
582 * Don't bother responding if the destination was a broadcast.
583 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
584 * tp->iss, and send a segment:
585 * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
586 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
587 * Fill in remote peer address fields if not previously specified.
588 * Enter SYN_RECEIVED state, and process any other fields of this
589 * segment in this state.
590 */
591 case TCPS_LISTEN: {
592 if (tiflags & TH_RST)
593 goto drop;
594 if (tiflags & TH_ACK)
595 goto dropwithreset;
596 if ((tiflags & TH_SYN) == 0)
597 goto drop;
598
599 /*
600 * This has way too many gotos...
601 * But a bit of spaghetti code never hurt anybody :)
602 */
603
604 /*
605 * If this is destined for the control address, then flag to
606 * tcp_ctl once connected, otherwise connect
607 */
608 /* TODO: IPv6 */
609 if (af == AF_INET &&
610 (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
611 slirp->vnetwork_addr.s_addr) {
612 if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
613 so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
614 /* May be an add exec */
615 for (ex_ptr = slirp->guestfwd_list; ex_ptr;
616 ex_ptr = ex_ptr->ex_next) {
617 if (ex_ptr->ex_fport == so->so_fport &&
618 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
619 so->so_state |= SS_CTL;
620 break;
621 }
622 }
623 if (so->so_state & SS_CTL) {
624 goto cont_input;
625 }
626 }
627 /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
628 }
629
630 if (so->so_emu & EMU_NOCONNECT) {
631 so->so_emu &= ~EMU_NOCONNECT;
632 goto cont_input;
633 }
634
635 if ((tcp_fconnect(so, so->so_ffamily) == -1) && (errno != EAGAIN) &&
636 (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
637 uint8_t code;
638 DEBUG_MISC(" tcp fconnect errno = %d-%s", errno, strerror(errno));
639 if (errno == ECONNREFUSED) {
640 /* ACK the SYN, send RST to refuse the connection */
641 tcp_respond(tp, ti, m, ti->ti_seq + 1, (tcp_seq)0,
642 TH_RST | TH_ACK, af);
643 } else {
644 switch (af) {
645 case AF_INET:
646 code = ICMP_UNREACH_NET;
647 if (errno == EHOSTUNREACH) {
648 code = ICMP_UNREACH_HOST;
649 }
650 break;
651 case AF_INET6:
652 code = ICMP6_UNREACH_NO_ROUTE;
653 if (errno == EHOSTUNREACH) {
654 code = ICMP6_UNREACH_ADDRESS;
655 }
656 break;
657 default:
658 g_assert_not_reached();
659 }
660 HTONL(ti->ti_seq); /* restore tcp header */
661 HTONL(ti->ti_ack);
662 HTONS(ti->ti_win);
663 HTONS(ti->ti_urp);
664 m->m_data -=
665 sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);
666 m->m_len +=
667 sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);
668 switch (af) {
669 case AF_INET:
670 m->m_data += sizeof(struct tcpiphdr) - sizeof(struct ip) -
671 sizeof(struct tcphdr);
672 m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct ip) -
673 sizeof(struct tcphdr);
674 *ip = save_ip;
675 icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
676 break;
677 case AF_INET6:
678 m->m_data += sizeof(struct tcpiphdr) -
679 (sizeof(struct ip6) + sizeof(struct tcphdr));
680 m->m_len -= sizeof(struct tcpiphdr) -
681 (sizeof(struct ip6) + sizeof(struct tcphdr));
682 *ip6 = save_ip6;
683 icmp6_send_error(m, ICMP6_UNREACH, code);
684 break;
685 default:
686 g_assert_not_reached();
687 }
688 }
689 tcp_close(tp);
690 m_free(m);
691 } else {
692 /*
693 * Haven't connected yet, save the current mbuf
694 * and ti, and return
695 * XXX Some OS's don't tell us whether the connect()
696 * succeeded or not. So we must time it out.
697 */
698 so->so_m = m;
699 so->so_ti = ti;
700 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
701 tp->t_state = TCPS_SYN_RECEIVED;
702 /*
703 * Initialize receive sequence numbers now so that we can send a
704 * valid RST if the remote end rejects our connection.
705 */
706 tp->irs = ti->ti_seq;
707 tcp_rcvseqinit(tp);
708 tcp_template(tp);
709 }
710 return;
711
712 cont_conn:
713 /* m==NULL
714 * Check if the connect succeeded
715 */
716 if (so->so_state & SS_NOFDREF) {
717 tp = tcp_close(tp);
718 goto dropwithreset;
719 }
720 cont_input:
721 tcp_template(tp);
722
723 if (optp)
724 tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
725
726 if (iss)
727 tp->iss = iss;
728 else
729 tp->iss = slirp->tcp_iss;
730 slirp->tcp_iss += TCP_ISSINCR / 2;
731 tp->irs = ti->ti_seq;
732 tcp_sendseqinit(tp);
733 tcp_rcvseqinit(tp);
734 tp->t_flags |= TF_ACKNOW;
735 tp->t_state = TCPS_SYN_RECEIVED;
736 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
737 goto trimthenstep6;
738 } /* case TCPS_LISTEN */
739
740 /*
741 * If the state is SYN_SENT:
742 * if seg contains an ACK, but not for our SYN, drop the input.
743 * if seg contains a RST, then drop the connection.
744 * if seg does not contain SYN, then drop it.
745 * Otherwise this is an acceptable SYN segment
746 * initialize tp->rcv_nxt and tp->irs
747 * if seg contains ack then advance tp->snd_una
748 * if SYN has been acked change to ESTABLISHED else SYN_RCVD state
749 * arrange for segment to be acked (eventually)
750 * continue processing rest of data/controls, beginning with URG
751 */
752 case TCPS_SYN_SENT:
753 if ((tiflags & TH_ACK) &&
754 (SEQ_LEQ(ti->ti_ack, tp->iss) || SEQ_GT(ti->ti_ack, tp->snd_max)))
755 goto dropwithreset;
756
757 if (tiflags & TH_RST) {
758 if (tiflags & TH_ACK) {
759 tcp_drop(tp, 0); /* XXX Check t_softerror! */
760 }
761 goto drop;
762 }
763
764 if ((tiflags & TH_SYN) == 0)
765 goto drop;
766 if (tiflags & TH_ACK) {
767 tp->snd_una = ti->ti_ack;
768 if (SEQ_LT(tp->snd_nxt, tp->snd_una))
769 tp->snd_nxt = tp->snd_una;
770 }
771
772 tp->t_timer[TCPT_REXMT] = 0;
773 tp->irs = ti->ti_seq;
774 tcp_rcvseqinit(tp);
775 tp->t_flags |= TF_ACKNOW;
776 if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
777 soisfconnected(so);
778 tp->t_state = TCPS_ESTABLISHED;
779
780 (void)tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
781 /*
782 * if we didn't have to retransmit the SYN,
783 * use its rtt as our initial srtt & rtt var.
784 */
785 if (tp->t_rtt)
786 tcp_xmit_timer(tp, tp->t_rtt);
787 } else
788 tp->t_state = TCPS_SYN_RECEIVED;
789
790 trimthenstep6:
791 /*
792 * Advance ti->ti_seq to correspond to first data byte.
793 * If data, trim to stay within window,
794 * dropping FIN if necessary.
795 */
796 ti->ti_seq++;
797 if (ti->ti_len > tp->rcv_wnd) {
798 todrop = ti->ti_len - tp->rcv_wnd;
799 m_adj(m, -todrop);
800 ti->ti_len = tp->rcv_wnd;
801 tiflags &= ~TH_FIN;
802 }
803 tp->snd_wl1 = ti->ti_seq - 1;
804 tp->rcv_up = ti->ti_seq;
805 goto step6;
806 } /* switch tp->t_state */
807 /*
808 * States other than LISTEN or SYN_SENT.
809 * Check that at least some bytes of segment are within
810 * receive window. If segment begins before rcv_nxt,
811 * drop leading data (and SYN); if nothing left, just ack.
812 */
813 todrop = tp->rcv_nxt - ti->ti_seq;
814 if (todrop > 0) {
815 if (tiflags & TH_SYN) {
816 tiflags &= ~TH_SYN;
817 ti->ti_seq++;
818 if (ti->ti_urp > 1)
819 ti->ti_urp--;
820 else
821 tiflags &= ~TH_URG;
822 todrop--;
823 }
824 /*
825 * Following if statement from Stevens, vol. 2, p. 960.
826 */
827 if (todrop > ti->ti_len ||
828 (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
829 /*
830 * Any valid FIN must be to the left of the window.
831 * At this point the FIN must be a duplicate or out
832 * of sequence; drop it.
833 */
834 tiflags &= ~TH_FIN;
835
836 /*
837 * Send an ACK to resynchronize and drop any data.
838 * But keep on processing for RST or ACK.
839 */
840 tp->t_flags |= TF_ACKNOW;
841 todrop = ti->ti_len;
842 }
843 m_adj(m, todrop);
844 ti->ti_seq += todrop;
845 ti->ti_len -= todrop;
846 if (ti->ti_urp > todrop)
847 ti->ti_urp -= todrop;
848 else {
849 tiflags &= ~TH_URG;
850 ti->ti_urp = 0;
851 }
852 }
853 /*
854 * If new data are received on a connection after the
855 * user processes are gone, then RST the other end.
856 */
857 if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT &&
858 ti->ti_len) {
859 tp = tcp_close(tp);
860 goto dropwithreset;
861 }
862
863 /*
864 * If segment ends after window, drop trailing data
865 * (and PUSH and FIN); if nothing left, just ACK.
866 */
867 todrop = (ti->ti_seq + ti->ti_len) - (tp->rcv_nxt + tp->rcv_wnd);
868 if (todrop > 0) {
869 if (todrop >= ti->ti_len) {
870 /*
871 * If a new connection request is received
872 * while in TIME_WAIT, drop the old connection
873 * and start over if the sequence numbers
874 * are above the previous ones.
875 */
876 if (tiflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT &&
877 SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
878 iss = tp->rcv_nxt + TCP_ISSINCR;
879 tp = tcp_close(tp);
880 goto findso;
881 }
882 /*
883 * If window is closed can only take segments at
884 * window edge, and have to drop data and PUSH from
885 * incoming segments. Continue processing, but
886 * remember to ack. Otherwise, drop segment
887 * and ack.
888 */
889 if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
890 tp->t_flags |= TF_ACKNOW;
891 } else {
892 goto dropafterack;
893 }
894 }
895 m_adj(m, -todrop);
896 ti->ti_len -= todrop;
897 tiflags &= ~(TH_PUSH | TH_FIN);
898 }
899
900 /*
901 * If the RST bit is set examine the state:
902 * SYN_RECEIVED STATE:
903 * If passive open, return to LISTEN state.
904 * If active open, inform user that connection was refused.
905 * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
906 * Inform user that connection was reset, and close tcb.
907 * CLOSING, LAST_ACK, TIME_WAIT STATES
908 * Close the tcb.
909 */
910 if (tiflags & TH_RST)
911 switch (tp->t_state) {
912 case TCPS_SYN_RECEIVED:
913 case TCPS_ESTABLISHED:
914 case TCPS_FIN_WAIT_1:
915 case TCPS_FIN_WAIT_2:
916 case TCPS_CLOSE_WAIT:
917 tp->t_state = TCPS_CLOSED;
918 tcp_close(tp);
919 goto drop;
920
921 case TCPS_CLOSING:
922 case TCPS_LAST_ACK:
923 case TCPS_TIME_WAIT:
924 tcp_close(tp);
925 goto drop;
926 }
927
928 /*
929 * If a SYN is in the window, then this is an
930 * error and we send an RST and drop the connection.
931 */
932 if (tiflags & TH_SYN) {
933 tp = tcp_drop(tp, 0);
934 goto dropwithreset;
935 }
936
937 /*
938 * If the ACK bit is off we drop the segment and return.
939 */
940 if ((tiflags & TH_ACK) == 0)
941 goto drop;
942
943 /*
944 * Ack processing.
945 */
946 switch (tp->t_state) {
947 /*
948 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
949 * ESTABLISHED state and continue processing, otherwise
950 * send an RST. una<=ack<=max
951 */
952 case TCPS_SYN_RECEIVED:
953
954 if (SEQ_GT(tp->snd_una, ti->ti_ack) || SEQ_GT(ti->ti_ack, tp->snd_max))
955 goto dropwithreset;
956 tp->t_state = TCPS_ESTABLISHED;
957 /*
958 * The sent SYN is ack'ed with our sequence number +1
959 * The first data byte already in the buffer will get
960 * lost if no correction is made. This is only needed for
961 * SS_CTL since the buffer is empty otherwise.
962 * tp->snd_una++; or:
963 */
964 tp->snd_una = ti->ti_ack;
965 if (so->so_state & SS_CTL) {
966 /* So tcp_ctl reports the right state */
967 ret = tcp_ctl(so);
968 if (ret == 1) {
969 soisfconnected(so);
970 so->so_state &= ~SS_CTL; /* success XXX */
971 } else if (ret == 2) {
972 so->so_state &= SS_PERSISTENT_MASK;
973 so->so_state |= SS_NOFDREF; /* CTL_CMD */
974 } else {
975 needoutput = 1;
976 tp->t_state = TCPS_FIN_WAIT_1;
977 }
978 } else {
979 soisfconnected(so);
980 }
981
982 (void)tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
983 tp->snd_wl1 = ti->ti_seq - 1;
984 /* Avoid ack processing; snd_una==ti_ack => dup ack */
985 goto synrx_to_est;
986 /* fall into ... */
987
988 /*
989 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
990 * ACKs. If the ack is in the range
991 * tp->snd_una < ti->ti_ack <= tp->snd_max
992 * then advance tp->snd_una to ti->ti_ack and drop
993 * data from the retransmission queue. If this ACK reflects
994 * more up to date window information we update our window information.
995 */
996 case TCPS_ESTABLISHED:
997 case TCPS_FIN_WAIT_1:
998 case TCPS_FIN_WAIT_2:
999 case TCPS_CLOSE_WAIT:
1000 case TCPS_CLOSING:
1001 case TCPS_LAST_ACK:
1002 case TCPS_TIME_WAIT:
1003
1004 if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
1005 if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
1006 DEBUG_MISC(" dup ack m = %p so = %p", m, so);
1007 /*
1008 * If we have outstanding data (other than
1009 * a window probe), this is a completely
1010 * duplicate ack (ie, window info didn't
1011 * change), the ack is the biggest we've
1012 * seen and we've seen exactly our rexmt
1013 * threshold of them, assume a packet
1014 * has been dropped and retransmit it.
1015 * Kludge snd_nxt & the congestion
1016 * window so we send only this one
1017 * packet.
1018 *
1019 * We know we're losing at the current
1020 * window size so do congestion avoidance
1021 * (set ssthresh to half the current window
1022 * and pull our congestion window back to
1023 * the new ssthresh).
1024 *
1025 * Dup acks mean that packets have left the
1026 * network (they're now cached at the receiver)
1027 * so bump cwnd by the amount in the receiver
1028 * to keep a constant cwnd packets in the
1029 * network.
1030 */
1031 if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una)
1032 tp->t_dupacks = 0;
1033 else if (++tp->t_dupacks == TCPREXMTTHRESH) {
1034 tcp_seq onxt = tp->snd_nxt;
1035 unsigned win =
1036 MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
1037
1038 if (win < 2)
1039 win = 2;
1040 tp->snd_ssthresh = win * tp->t_maxseg;
1041 tp->t_timer[TCPT_REXMT] = 0;
1042 tp->t_rtt = 0;
1043 tp->snd_nxt = ti->ti_ack;
1044 tp->snd_cwnd = tp->t_maxseg;
1045 (void)tcp_output(tp);
1046 tp->snd_cwnd =
1047 tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks;
1048 if (SEQ_GT(onxt, tp->snd_nxt))
1049 tp->snd_nxt = onxt;
1050 goto drop;
1051 } else if (tp->t_dupacks > TCPREXMTTHRESH) {
1052 tp->snd_cwnd += tp->t_maxseg;
1053 (void)tcp_output(tp);
1054 goto drop;
1055 }
1056 } else
1057 tp->t_dupacks = 0;
1058 break;
1059 }
1060 synrx_to_est:
1061 /*
1062 * If the congestion window was inflated to account
1063 * for the other side's cached packets, retract it.
1064 */
1065 if (tp->t_dupacks > TCPREXMTTHRESH && tp->snd_cwnd > tp->snd_ssthresh)
1066 tp->snd_cwnd = tp->snd_ssthresh;
1067 tp->t_dupacks = 0;
1068 if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
1069 goto dropafterack;
1070 }
1071 acked = ti->ti_ack - tp->snd_una;
1072
1073 /*
1074 * If transmit timer is running and timed sequence
1075 * number was acked, update smoothed round trip time.
1076 * Since we now have an rtt measurement, cancel the
1077 * timer backoff (cf., Phil Karn's retransmit alg.).
1078 * Recompute the initial retransmit timer.
1079 */
1080 if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
1081 tcp_xmit_timer(tp, tp->t_rtt);
1082
1083 /*
1084 * If all outstanding data is acked, stop retransmit
1085 * timer and remember to restart (more output or persist).
1086 * If there is more data to be acked, restart retransmit
1087 * timer, using current (possibly backed-off) value.
1088 */
1089 if (ti->ti_ack == tp->snd_max) {
1090 tp->t_timer[TCPT_REXMT] = 0;
1091 needoutput = 1;
1092 } else if (tp->t_timer[TCPT_PERSIST] == 0)
1093 tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
1094 /*
1095 * When new data is acked, open the congestion window.
1096 * If the window gives us less than ssthresh packets
1097 * in flight, open exponentially (maxseg per packet).
1098 * Otherwise open linearly: maxseg per window
1099 * (maxseg^2 / cwnd per packet).
1100 */
1101 {
1102 register unsigned cw = tp->snd_cwnd;
1103 register unsigned incr = tp->t_maxseg;
1104
1105 if (cw > tp->snd_ssthresh)
1106 incr = incr * incr / cw;
1107 tp->snd_cwnd = MIN(cw + incr, TCP_MAXWIN << tp->snd_scale);
1108 }
1109 if (acked > so->so_snd.sb_cc) {
1110 tp->snd_wnd -= so->so_snd.sb_cc;
1111 sodrop(so, (int)so->so_snd.sb_cc);
1112 ourfinisacked = 1;
1113 } else {
1114 sodrop(so, acked);
1115 tp->snd_wnd -= acked;
1116 ourfinisacked = 0;
1117 }
1118 tp->snd_una = ti->ti_ack;
1119 if (SEQ_LT(tp->snd_nxt, tp->snd_una))
1120 tp->snd_nxt = tp->snd_una;
1121
1122 switch (tp->t_state) {
1123 /*
1124 * In FIN_WAIT_1 STATE in addition to the processing
1125 * for the ESTABLISHED state if our FIN is now acknowledged
1126 * then enter FIN_WAIT_2.
1127 */
1128 case TCPS_FIN_WAIT_1:
1129 if (ourfinisacked) {
1130 /*
1131 * If we can't receive any more
1132 * data, then closing user can proceed.
1133 * Starting the timer is contrary to the
1134 * specification, but if we don't get a FIN
1135 * we'll hang forever.
1136 */
1137 if (so->so_state & SS_FCANTRCVMORE) {
1138 tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
1139 }
1140 tp->t_state = TCPS_FIN_WAIT_2;
1141 }
1142 break;
1143
1144 /*
1145 * In CLOSING STATE in addition to the processing for
1146 * the ESTABLISHED state if the ACK acknowledges our FIN
1147 * then enter the TIME-WAIT state, otherwise ignore
1148 * the segment.
1149 */
1150 case TCPS_CLOSING:
1151 if (ourfinisacked) {
1152 tp->t_state = TCPS_TIME_WAIT;
1153 tcp_canceltimers(tp);
1154 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
1155 }
1156 break;
1157
1158 /*
1159 * In LAST_ACK, we may still be waiting for data to drain
1160 * and/or to be acked, as well as for the ack of our FIN.
1161 * If our FIN is now acknowledged, delete the TCB,
1162 * enter the closed state and return.
1163 */
1164 case TCPS_LAST_ACK:
1165 if (ourfinisacked) {
1166 tcp_close(tp);
1167 goto drop;
1168 }
1169 break;
1170
1171 /*
1172 * In TIME_WAIT state the only thing that should arrive
1173 * is a retransmission of the remote FIN. Acknowledge
1174 * it and restart the finack timer.
1175 */
1176 case TCPS_TIME_WAIT:
1177 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
1178 goto dropafterack;
1179 }
1180 } /* switch(tp->t_state) */
1181
1182 step6:
1183 /*
1184 * Update window information.
1185 * Don't look at window if no ACK: TAC's send garbage on first SYN.
1186 */
1187 if ((tiflags & TH_ACK) &&
1188 (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
1189 (tp->snd_wl1 == ti->ti_seq &&
1190 (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
1191 (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
1192 tp->snd_wnd = tiwin;
1193 tp->snd_wl1 = ti->ti_seq;
1194 tp->snd_wl2 = ti->ti_ack;
1195 if (tp->snd_wnd > tp->max_sndwnd)
1196 tp->max_sndwnd = tp->snd_wnd;
1197 needoutput = 1;
1198 }
1199
1200 /*
1201 * Process segments with URG.
1202 */
1203 if ((tiflags & TH_URG) && ti->ti_urp &&
1204 TCPS_HAVERCVDFIN(tp->t_state) == 0) {
1205 /*
1206 * This is a kludge, but if we receive and accept
1207 * random urgent pointers, we'll crash in
1208 * soreceive. It's hard to imagine someone
1209 * actually wanting to send this much urgent data.
1210 */
1211 if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {
1212 ti->ti_urp = 0;
1213 tiflags &= ~TH_URG;
1214 goto dodata;
1215 }
1216 /*
1217 * If this segment advances the known urgent pointer,
1218 * then mark the data stream. This should not happen
1219 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
1220 * a FIN has been received from the remote side.
1221 * In these states we ignore the URG.
1222 *
1223 * According to RFC961 (Assigned Protocols),
1224 * the urgent pointer points to the last octet
1225 * of urgent data. We continue, however,
1226 * to consider it to indicate the first octet
1227 * of data past the urgent section as the original
1228 * spec states (in one of two places).
1229 */
1230 if (SEQ_GT(ti->ti_seq + ti->ti_urp, tp->rcv_up)) {
1231 tp->rcv_up = ti->ti_seq + ti->ti_urp;
1232 so->so_urgc =
1233 so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt); /* -1; */
1234 tp->rcv_up = ti->ti_seq + ti->ti_urp;
1235 }
1236 } else
1237 /*
1238 * If no out of band data is expected,
1239 * pull receive urgent pointer along
1240 * with the receive window.
1241 */
1242 if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
1243 tp->rcv_up = tp->rcv_nxt;
1244 dodata:
1245
1246 /*
1247 * If this is a small packet, then ACK now - with Nagel
1248 * congestion avoidance sender won't send more until
1249 * he gets an ACK.
1250 */
1251 if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
1252 ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
1253 tp->t_flags |= TF_ACKNOW;
1254 }
1255
1256 /*
1257 * Process the segment text, merging it into the TCP sequencing queue,
1258 * and arranging for acknowledgment of receipt if necessary.
1259 * This process logically involves adjusting tp->rcv_wnd as data
1260 * is presented to the user (this happens in tcp_usrreq.c,
1261 * case PRU_RCVD). If a FIN has already been received on this
1262 * connection then we just ignore the text.
1263 */
1264 if ((ti->ti_len || (tiflags & TH_FIN)) &&
1265 TCPS_HAVERCVDFIN(tp->t_state) == 0) {
1266 TCP_REASS(tp, ti, m, so, tiflags);
1267 } else {
1268 m_free(m);
1269 tiflags &= ~TH_FIN;
1270 }
1271
1272 /*
1273 * If FIN is received ACK the FIN and let the user know
1274 * that the connection is closing.
1275 */
1276 if (tiflags & TH_FIN) {
1277 if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
1278 /*
1279 * If we receive a FIN we can't send more data,
1280 * set it SS_FDRAIN
1281 * Shutdown the socket if there is no rx data in the
1282 * buffer.
1283 * soread() is called on completion of shutdown() and
1284 * will got to TCPS_LAST_ACK, and use tcp_output()
1285 * to send the FIN.
1286 */
1287 sofwdrain(so);
1288
1289 tp->t_flags |= TF_ACKNOW;
1290 tp->rcv_nxt++;
1291 }
1292 switch (tp->t_state) {
1293 /*
1294 * In SYN_RECEIVED and ESTABLISHED STATES
1295 * enter the CLOSE_WAIT state.
1296 */
1297 case TCPS_SYN_RECEIVED:
1298 case TCPS_ESTABLISHED:
1299 if (so->so_emu == EMU_CTL) /* no shutdown on socket */
1300 tp->t_state = TCPS_LAST_ACK;
1301 else
1302 tp->t_state = TCPS_CLOSE_WAIT;
1303 break;
1304
1305 /*
1306 * If still in FIN_WAIT_1 STATE FIN has not been acked so
1307 * enter the CLOSING state.
1308 */
1309 case TCPS_FIN_WAIT_1:
1310 tp->t_state = TCPS_CLOSING;
1311 break;
1312
1313 /*
1314 * In FIN_WAIT_2 state enter the TIME_WAIT state,
1315 * starting the time-wait timer, turning off the other
1316 * standard timers.
1317 */
1318 case TCPS_FIN_WAIT_2:
1319 tp->t_state = TCPS_TIME_WAIT;
1320 tcp_canceltimers(tp);
1321 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
1322 break;
1323
1324 /*
1325 * In TIME_WAIT state restart the 2 MSL time_wait timer.
1326 */
1327 case TCPS_TIME_WAIT:
1328 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
1329 break;
1330 }
1331 }
1332
1333 /*
1334 * Return any desired output.
1335 */
1336 if (needoutput || (tp->t_flags & TF_ACKNOW)) {
1337 (void)tcp_output(tp);
1338 }
1339 return;
1340
1341 dropafterack:
1342 /*
1343 * Generate an ACK dropping incoming segment if it occupies
1344 * sequence space, where the ACK reflects our state.
1345 */
1346 if (tiflags & TH_RST)
1347 goto drop;
1348 m_free(m);
1349 tp->t_flags |= TF_ACKNOW;
1350 (void)tcp_output(tp);
1351 return;
1352
1353 dropwithreset:
1354 /* reuses m if m!=NULL, m_free() unnecessary */
1355 if (tiflags & TH_ACK)
1356 tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST, af);
1357 else {
1358 if (tiflags & TH_SYN)
1359 ti->ti_len++;
1360 tcp_respond(tp, ti, m, ti->ti_seq + ti->ti_len, (tcp_seq)0,
1361 TH_RST | TH_ACK, af);
1362 }
1363
1364 return;
1365
1366 drop:
1367 /*
1368 * Drop space held by incoming segment and return.
1369 */
1370 m_free(m);
1371 }
1372
1373 static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt,
1374 struct tcpiphdr *ti)
1375 {
1376 uint16_t mss;
1377 int opt, optlen;
1378
1379 DEBUG_CALL("tcp_dooptions");
1380 DEBUG_ARG("tp = %p cnt=%i", tp, cnt);
1381
1382 for (; cnt > 0; cnt -= optlen, cp += optlen) {
1383 opt = cp[0];
1384 if (opt == TCPOPT_EOL)
1385 break;
1386 if (opt == TCPOPT_NOP)
1387 optlen = 1;
1388 else {
1389 optlen = cp[1];
1390 if (optlen <= 0)
1391 break;
1392 }
1393 switch (opt) {
1394 default:
1395 continue;
1396
1397 case TCPOPT_MAXSEG:
1398 if (optlen != TCPOLEN_MAXSEG)
1399 continue;
1400 if (!(ti->ti_flags & TH_SYN))
1401 continue;
1402 memcpy((char *)&mss, (char *)cp + 2, sizeof(mss));
1403 NTOHS(mss);
1404 (void)tcp_mss(tp, mss); /* sets t_maxseg */
1405 break;
1406 }
1407 }
1408 }
1409
1410 /*
1411 * Collect new round-trip time estimate
1412 * and update averages and current timeout.
1413 */
1414
1415 static void tcp_xmit_timer(register struct tcpcb *tp, int rtt)
1416 {
1417 register short delta;
1418
1419 DEBUG_CALL("tcp_xmit_timer");
1420 DEBUG_ARG("tp = %p", tp);
1421 DEBUG_ARG("rtt = %d", rtt);
1422
1423 if (tp->t_srtt != 0) {
1424 /*
1425 * srtt is stored as fixed point with 3 bits after the
1426 * binary point (i.e., scaled by 8). The following magic
1427 * is equivalent to the smoothing algorithm in rfc793 with
1428 * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
1429 * point). Adjust rtt to origin 0.
1430 */
1431 delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
1432 if ((tp->t_srtt += delta) <= 0)
1433 tp->t_srtt = 1;
1434 /*
1435 * We accumulate a smoothed rtt variance (actually, a
1436 * smoothed mean difference), then set the retransmit
1437 * timer to smoothed rtt + 4 times the smoothed variance.
1438 * rttvar is stored as fixed point with 2 bits after the
1439 * binary point (scaled by 4). The following is
1440 * equivalent to rfc793 smoothing with an alpha of .75
1441 * (rttvar = rttvar*3/4 + |delta| / 4). This replaces
1442 * rfc793's wired-in beta.
1443 */
1444 if (delta < 0)
1445 delta = -delta;
1446 delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
1447 if ((tp->t_rttvar += delta) <= 0)
1448 tp->t_rttvar = 1;
1449 } else {
1450 /*
1451 * No rtt measurement yet - use the unsmoothed rtt.
1452 * Set the variance to half the rtt (so our first
1453 * retransmit happens at 3*rtt).
1454 */
1455 tp->t_srtt = rtt << TCP_RTT_SHIFT;
1456 tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
1457 }
1458 tp->t_rtt = 0;
1459 tp->t_rxtshift = 0;
1460
1461 /*
1462 * the retransmit should happen at rtt + 4 * rttvar.
1463 * Because of the way we do the smoothing, srtt and rttvar
1464 * will each average +1/2 tick of bias. When we compute
1465 * the retransmit timer, we want 1/2 tick of rounding and
1466 * 1 extra tick because of +-1/2 tick uncertainty in the
1467 * firing of the timer. The bias will give us exactly the
1468 * 1.5 tick we need. But, because the bias is
1469 * statistical, we have to test that we don't drop below
1470 * the minimum feasible timer (which is 2 ticks).
1471 */
1472 TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), (short)tp->t_rttmin,
1473 TCPTV_REXMTMAX); /* XXX */
1474
1475 /*
1476 * We received an ack for a packet that wasn't retransmitted;
1477 * it is probably safe to discard any error indications we've
1478 * received recently. This isn't quite right, but close enough
1479 * for now (a route might have failed after we sent a segment,
1480 * and the return path might not be symmetrical).
1481 */
1482 tp->t_softerror = 0;
1483 }
1484
1485 /*
1486 * Determine a reasonable value for maxseg size.
1487 * If the route is known, check route for mtu.
1488 * If none, use an mss that can be handled on the outgoing
1489 * interface without forcing IP to fragment; if bigger than
1490 * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
1491 * to utilize large mbufs. If no route is found, route has no mtu,
1492 * or the destination isn't local, use a default, hopefully conservative
1493 * size (usually 512 or the default IP max size, but no more than the mtu
1494 * of the interface), as we can't discover anything about intervening
1495 * gateways or networks. We also initialize the congestion/slow start
1496 * window to be a single segment if the destination isn't local.
1497 * While looking at the routing entry, we also initialize other path-dependent
1498 * parameters from pre-set or cached values in the routing entry.
1499 */
1500
1501 int tcp_mss(struct tcpcb *tp, unsigned offer)
1502 {
1503 struct socket *so = tp->t_socket;
1504 int mss;
1505
1506 DEBUG_CALL("tcp_mss");
1507 DEBUG_ARG("tp = %p", tp);
1508 DEBUG_ARG("offer = %d", offer);
1509
1510 switch (so->so_ffamily) {
1511 case AF_INET:
1512 mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) -
1513 sizeof(struct tcphdr) - sizeof(struct ip);
1514 break;
1515 case AF_INET6:
1516 mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) -
1517 sizeof(struct tcphdr) - sizeof(struct ip6);
1518 break;
1519 default:
1520 g_assert_not_reached();
1521 }
1522
1523 if (offer)
1524 mss = MIN(mss, offer);
1525 mss = MAX(mss, 32);
1526 if (mss < tp->t_maxseg || offer != 0)
1527 tp->t_maxseg = MIN(mss, TCP_MAXSEG_MAX);
1528
1529 tp->snd_cwnd = mss;
1530
1531 sbreserve(&so->so_snd,
1532 TCP_SNDSPACE +
1533 ((TCP_SNDSPACE % mss) ? (mss - (TCP_SNDSPACE % mss)) : 0));
1534 sbreserve(&so->so_rcv,
1535 TCP_RCVSPACE +
1536 ((TCP_RCVSPACE % mss) ? (mss - (TCP_RCVSPACE % mss)) : 0));
1537
1538 DEBUG_MISC(" returning mss = %d", mss);
1539
1540 return mss;
1541 }
+0
-516
vendor/libslirp/src/tcp_output.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93
30 * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP
35 * Copyright (c) 1995 Danny Gasparovski.
36 */
37
38 #include "slirp.h"
39
40 static const uint8_t tcp_outflags[TCP_NSTATES] = {
41 TH_RST | TH_ACK, 0, TH_SYN, TH_SYN | TH_ACK,
42 TH_ACK, TH_ACK, TH_FIN | TH_ACK, TH_FIN | TH_ACK,
43 TH_FIN | TH_ACK, TH_ACK, TH_ACK,
44 };
45
46
47 #undef MAX_TCPOPTLEN
48 #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */
49
50 /*
51 * Tcp output routine: figure out what should be sent and send it.
52 */
53 int tcp_output(struct tcpcb *tp)
54 {
55 register struct socket *so = tp->t_socket;
56 register long len, win;
57 int off, flags, error;
58 register struct mbuf *m;
59 register struct tcpiphdr *ti, tcpiph_save;
60 struct ip *ip;
61 struct ip6 *ip6;
62 uint8_t opt[MAX_TCPOPTLEN];
63 unsigned optlen, hdrlen;
64 int idle, sendalot;
65
66 DEBUG_CALL("tcp_output");
67 DEBUG_ARG("tp = %p", tp);
68
69 /*
70 * Determine length of data that should be transmitted,
71 * and flags that will be used.
72 * If there is some data or critical controls (SYN, RST)
73 * to send, then transmit; otherwise, investigate further.
74 */
75 idle = (tp->snd_max == tp->snd_una);
76 if (idle && tp->t_idle >= tp->t_rxtcur)
77 /*
78 * We have been idle for "a while" and no acks are
79 * expected to clock out any data we send --
80 * slow start to get ack "clock" running again.
81 */
82 tp->snd_cwnd = tp->t_maxseg;
83 again:
84 sendalot = 0;
85 off = tp->snd_nxt - tp->snd_una;
86 win = MIN(tp->snd_wnd, tp->snd_cwnd);
87
88 flags = tcp_outflags[tp->t_state];
89
90 DEBUG_MISC(" --- tcp_output flags = 0x%x", flags);
91
92 /*
93 * If in persist timeout with window of 0, send 1 byte.
94 * Otherwise, if window is small but nonzero
95 * and timer expired, we will send what we can
96 * and go to transmit state.
97 */
98 if (tp->t_force) {
99 if (win == 0) {
100 /*
101 * If we still have some data to send, then
102 * clear the FIN bit. Usually this would
103 * happen below when it realizes that we
104 * aren't sending all the data. However,
105 * if we have exactly 1 byte of unset data,
106 * then it won't clear the FIN bit below,
107 * and if we are in persist state, we wind
108 * up sending the packet without recording
109 * that we sent the FIN bit.
110 *
111 * We can't just blindly clear the FIN bit,
112 * because if we don't have any more data
113 * to send then the probe will be the FIN
114 * itself.
115 */
116 if (off < so->so_snd.sb_cc)
117 flags &= ~TH_FIN;
118 win = 1;
119 } else {
120 tp->t_timer[TCPT_PERSIST] = 0;
121 tp->t_rxtshift = 0;
122 }
123 }
124
125 len = MIN(so->so_snd.sb_cc, win) - off;
126
127 if (len < 0) {
128 /*
129 * If FIN has been sent but not acked,
130 * but we haven't been called to retransmit,
131 * len will be -1. Otherwise, window shrank
132 * after we sent into it. If window shrank to 0,
133 * cancel pending retransmit and pull snd_nxt
134 * back to (closed) window. We will enter persist
135 * state below. If the window didn't close completely,
136 * just wait for an ACK.
137 */
138 len = 0;
139 if (win == 0) {
140 tp->t_timer[TCPT_REXMT] = 0;
141 tp->snd_nxt = tp->snd_una;
142 }
143 }
144
145 if (len > tp->t_maxseg) {
146 len = tp->t_maxseg;
147 sendalot = 1;
148 }
149 if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
150 flags &= ~TH_FIN;
151
152 win = sbspace(&so->so_rcv);
153
154 /*
155 * Sender silly window avoidance. If connection is idle
156 * and can send all data, a maximum segment,
157 * at least a maximum default-size segment do it,
158 * or are forced, do it; otherwise don't bother.
159 * If peer's buffer is tiny, then send
160 * when window is at least half open.
161 * If retransmitting (possibly after persist timer forced us
162 * to send into a small window), then must resend.
163 */
164 if (len) {
165 if (len == tp->t_maxseg)
166 goto send;
167 if ((1 || idle || tp->t_flags & TF_NODELAY) &&
168 len + off >= so->so_snd.sb_cc)
169 goto send;
170 if (tp->t_force)
171 goto send;
172 if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
173 goto send;
174 if (SEQ_LT(tp->snd_nxt, tp->snd_max))
175 goto send;
176 }
177
178 /*
179 * Compare available window to amount of window
180 * known to peer (as advertised window less
181 * next expected input). If the difference is at least two
182 * max size segments, or at least 50% of the maximum possible
183 * window, then want to send a window update to peer.
184 */
185 if (win > 0) {
186 /*
187 * "adv" is the amount we can increase the window,
188 * taking into account that we are limited by
189 * TCP_MAXWIN << tp->rcv_scale.
190 */
191 long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) -
192 (tp->rcv_adv - tp->rcv_nxt);
193
194 if (adv >= (long)(2 * tp->t_maxseg))
195 goto send;
196 if (2 * adv >= (long)so->so_rcv.sb_datalen)
197 goto send;
198 }
199
200 /*
201 * Send if we owe peer an ACK.
202 */
203 if (tp->t_flags & TF_ACKNOW)
204 goto send;
205 if (flags & (TH_SYN | TH_RST))
206 goto send;
207 if (SEQ_GT(tp->snd_up, tp->snd_una))
208 goto send;
209 /*
210 * If our state indicates that FIN should be sent
211 * and we have not yet done so, or we're retransmitting the FIN,
212 * then we need to send.
213 */
214 if (flags & TH_FIN &&
215 ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
216 goto send;
217
218 /*
219 * TCP window updates are not reliable, rather a polling protocol
220 * using ``persist'' packets is used to insure receipt of window
221 * updates. The three ``states'' for the output side are:
222 * idle not doing retransmits or persists
223 * persisting to move a small or zero window
224 * (re)transmitting and thereby not persisting
225 *
226 * tp->t_timer[TCPT_PERSIST]
227 * is set when we are in persist state.
228 * tp->t_force
229 * is set when we are called to send a persist packet.
230 * tp->t_timer[TCPT_REXMT]
231 * is set when we are retransmitting
232 * The output side is idle when both timers are zero.
233 *
234 * If send window is too small, there is data to transmit, and no
235 * retransmit or persist is pending, then go to persist state.
236 * If nothing happens soon, send when timer expires:
237 * if window is nonzero, transmit what we can,
238 * otherwise force out a byte.
239 */
240 if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
241 tp->t_timer[TCPT_PERSIST] == 0) {
242 tp->t_rxtshift = 0;
243 tcp_setpersist(tp);
244 }
245
246 /*
247 * No reason to send a segment, just return.
248 */
249 return (0);
250
251 send:
252 /*
253 * Before ESTABLISHED, force sending of initial options
254 * unless TCP set not to do any options.
255 * NOTE: we assume that the IP/TCP header plus TCP options
256 * always fit in a single mbuf, leaving room for a maximum
257 * link header, i.e.
258 * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
259 */
260 optlen = 0;
261 hdrlen = sizeof(struct tcpiphdr);
262 if (flags & TH_SYN) {
263 tp->snd_nxt = tp->iss;
264 if ((tp->t_flags & TF_NOOPT) == 0) {
265 uint16_t mss;
266
267 opt[0] = TCPOPT_MAXSEG;
268 opt[1] = 4;
269 mss = htons((uint16_t)tcp_mss(tp, 0));
270 memcpy((char *)(opt + 2), (char *)&mss, sizeof(mss));
271 optlen = 4;
272 }
273 }
274
275 hdrlen += optlen;
276
277 /*
278 * Adjust data length if insertion of options will
279 * bump the packet length beyond the t_maxseg length.
280 */
281 if (len > tp->t_maxseg - optlen) {
282 len = tp->t_maxseg - optlen;
283 sendalot = 1;
284 }
285
286 /*
287 * Grab a header mbuf, attaching a copy of data to
288 * be transmitted, and initialize the header from
289 * the template for sends on this connection.
290 */
291 if (len) {
292 m = m_get(so->slirp);
293 if (m == NULL) {
294 error = 1;
295 goto out;
296 }
297 m->m_data += IF_MAXLINKHDR;
298 m->m_len = hdrlen;
299
300 sbcopy(&so->so_snd, off, (int)len, mtod(m, char *) + hdrlen);
301 m->m_len += len;
302
303 /*
304 * If we're sending everything we've got, set PUSH.
305 * (This will keep happy those implementations which only
306 * give data to the user when a buffer fills or
307 * a PUSH comes in.)
308 */
309 if (off + len == so->so_snd.sb_cc)
310 flags |= TH_PUSH;
311 } else {
312 m = m_get(so->slirp);
313 if (m == NULL) {
314 error = 1;
315 goto out;
316 }
317 m->m_data += IF_MAXLINKHDR;
318 m->m_len = hdrlen;
319 }
320
321 ti = mtod(m, struct tcpiphdr *);
322
323 memcpy((char *)ti, &tp->t_template, sizeof(struct tcpiphdr));
324
325 /*
326 * Fill in fields, remembering maximum advertised
327 * window for use in delaying messages about window sizes.
328 * If resending a FIN, be sure not to use a new sequence number.
329 */
330 if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
331 tp->snd_nxt == tp->snd_max)
332 tp->snd_nxt--;
333 /*
334 * If we are doing retransmissions, then snd_nxt will
335 * not reflect the first unsent octet. For ACK only
336 * packets, we do not want the sequence number of the
337 * retransmitted packet, we want the sequence number
338 * of the next unsent octet. So, if there is no data
339 * (and no SYN or FIN), use snd_max instead of snd_nxt
340 * when filling in ti_seq. But if we are in persist
341 * state, snd_max might reflect one byte beyond the
342 * right edge of the window, so use snd_nxt in that
343 * case, since we know we aren't doing a retransmission.
344 * (retransmit and persist are mutually exclusive...)
345 */
346 if (len || (flags & (TH_SYN | TH_FIN)) || tp->t_timer[TCPT_PERSIST])
347 ti->ti_seq = htonl(tp->snd_nxt);
348 else
349 ti->ti_seq = htonl(tp->snd_max);
350 ti->ti_ack = htonl(tp->rcv_nxt);
351 if (optlen) {
352 memcpy((char *)(ti + 1), (char *)opt, optlen);
353 ti->ti_off = (sizeof(struct tcphdr) + optlen) >> 2;
354 }
355 ti->ti_flags = flags;
356 /*
357 * Calculate receive window. Don't shrink window,
358 * but avoid silly window syndrome.
359 */
360 if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg)
361 win = 0;
362 if (win > (long)TCP_MAXWIN << tp->rcv_scale)
363 win = (long)TCP_MAXWIN << tp->rcv_scale;
364 if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
365 win = (long)(tp->rcv_adv - tp->rcv_nxt);
366 ti->ti_win = htons((uint16_t)(win >> tp->rcv_scale));
367
368 if (SEQ_GT(tp->snd_up, tp->snd_una)) {
369 ti->ti_urp = htons((uint16_t)(tp->snd_up - ntohl(ti->ti_seq)));
370 ti->ti_flags |= TH_URG;
371 } else
372 /*
373 * If no urgent pointer to send, then we pull
374 * the urgent pointer to the left edge of the send window
375 * so that it doesn't drift into the send window on sequence
376 * number wraparound.
377 */
378 tp->snd_up = tp->snd_una; /* drag it along */
379
380 /*
381 * Put TCP length in extended header, and then
382 * checksum extended header and data.
383 */
384 if (len + optlen)
385 ti->ti_len = htons((uint16_t)(sizeof(struct tcphdr) + optlen + len));
386 ti->ti_sum = cksum(m, (int)(hdrlen + len));
387
388 /*
389 * In transmit state, time the transmission and arrange for
390 * the retransmit. In persist state, just set snd_max.
391 */
392 if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {
393 tcp_seq startseq = tp->snd_nxt;
394
395 /*
396 * Advance snd_nxt over sequence space of this segment.
397 */
398 if (flags & (TH_SYN | TH_FIN)) {
399 if (flags & TH_SYN)
400 tp->snd_nxt++;
401 if (flags & TH_FIN) {
402 tp->snd_nxt++;
403 tp->t_flags |= TF_SENTFIN;
404 }
405 }
406 tp->snd_nxt += len;
407 if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
408 tp->snd_max = tp->snd_nxt;
409 /*
410 * Time this transmission if not a retransmission and
411 * not currently timing anything.
412 */
413 if (tp->t_rtt == 0) {
414 tp->t_rtt = 1;
415 tp->t_rtseq = startseq;
416 }
417 }
418
419 /*
420 * Set retransmit timer if not currently set,
421 * and not doing an ack or a keep-alive probe.
422 * Initial value for retransmit timer is smoothed
423 * round-trip time + 2 * round-trip time variance.
424 * Initialize shift counter which is used for backoff
425 * of retransmit time.
426 */
427 if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) {
428 tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
429 if (tp->t_timer[TCPT_PERSIST]) {
430 tp->t_timer[TCPT_PERSIST] = 0;
431 tp->t_rxtshift = 0;
432 }
433 }
434 } else if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
435 tp->snd_max = tp->snd_nxt + len;
436
437 /*
438 * Fill in IP length and desired time to live and
439 * send to IP level. There should be a better way
440 * to handle ttl and tos; we could keep them in
441 * the template, but need a way to checksum without them.
442 */
443 m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
444 tcpiph_save = *mtod(m, struct tcpiphdr *);
445
446 switch (so->so_ffamily) {
447 case AF_INET:
448 m->m_data +=
449 sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
450 m->m_len -=
451 sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
452 ip = mtod(m, struct ip *);
453
454 ip->ip_len = m->m_len;
455 ip->ip_dst = tcpiph_save.ti_dst;
456 ip->ip_src = tcpiph_save.ti_src;
457 ip->ip_p = tcpiph_save.ti_pr;
458
459 ip->ip_ttl = IPDEFTTL;
460 ip->ip_tos = so->so_iptos;
461 error = ip_output(so, m);
462 break;
463
464 case AF_INET6:
465 m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr) -
466 sizeof(struct ip6);
467 m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr) -
468 sizeof(struct ip6);
469 ip6 = mtod(m, struct ip6 *);
470
471 ip6->ip_pl = tcpiph_save.ti_len;
472 ip6->ip_dst = tcpiph_save.ti_dst6;
473 ip6->ip_src = tcpiph_save.ti_src6;
474 ip6->ip_nh = tcpiph_save.ti_nh6;
475
476 error = ip6_output(so, m, 0);
477 break;
478
479 default:
480 g_assert_not_reached();
481 }
482
483 if (error) {
484 out:
485 return (error);
486 }
487
488 /*
489 * Data sent (as far as we can tell).
490 * If this advertises a larger window than any other segment,
491 * then remember the size of the advertised window.
492 * Any pending ACK has now been sent.
493 */
494 if (win > 0 && SEQ_GT(tp->rcv_nxt + win, tp->rcv_adv))
495 tp->rcv_adv = tp->rcv_nxt + win;
496 tp->last_ack_sent = tp->rcv_nxt;
497 tp->t_flags &= ~(TF_ACKNOW | TF_DELACK);
498 if (sendalot)
499 goto again;
500
501 return (0);
502 }
503
504 void tcp_setpersist(struct tcpcb *tp)
505 {
506 int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
507
508 /*
509 * Start/restart persistence timer.
510 */
511 TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], t * tcp_backoff[tp->t_rxtshift],
512 TCPTV_PERSMIN, TCPTV_PERSMAX);
513 if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
514 tp->t_rxtshift++;
515 }
+0
-971
vendor/libslirp/src/tcp_subr.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
30 * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP
35 * Copyright (c) 1995 Danny Gasparovski.
36 */
37
38 #include "slirp.h"
39
40 /* patchable/settable parameters for tcp */
41 /* Don't do rfc1323 performance enhancements */
42 #define TCP_DO_RFC1323 0
43
44 /*
45 * Tcp initialization
46 */
47 void tcp_init(Slirp *slirp)
48 {
49 slirp->tcp_iss = 1; /* wrong */
50 slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
51 slirp->tcp_last_so = &slirp->tcb;
52 }
53
54 void tcp_cleanup(Slirp *slirp)
55 {
56 while (slirp->tcb.so_next != &slirp->tcb) {
57 tcp_close(sototcpcb(slirp->tcb.so_next));
58 }
59 }
60
61 /*
62 * Create template to be used to send tcp packets on a connection.
63 * Call after host entry created, fills
64 * in a skeletal tcp/ip header, minimizing the amount of work
65 * necessary when the connection is used.
66 */
67 void tcp_template(struct tcpcb *tp)
68 {
69 struct socket *so = tp->t_socket;
70 register struct tcpiphdr *n = &tp->t_template;
71
72 n->ti_mbuf = NULL;
73 memset(&n->ti, 0, sizeof(n->ti));
74 n->ti_x0 = 0;
75 switch (so->so_ffamily) {
76 case AF_INET:
77 n->ti_pr = IPPROTO_TCP;
78 n->ti_len = htons(sizeof(struct tcphdr));
79 n->ti_src = so->so_faddr;
80 n->ti_dst = so->so_laddr;
81 n->ti_sport = so->so_fport;
82 n->ti_dport = so->so_lport;
83 break;
84
85 case AF_INET6:
86 n->ti_nh6 = IPPROTO_TCP;
87 n->ti_len = htons(sizeof(struct tcphdr));
88 n->ti_src6 = so->so_faddr6;
89 n->ti_dst6 = so->so_laddr6;
90 n->ti_sport = so->so_fport6;
91 n->ti_dport = so->so_lport6;
92 break;
93
94 default:
95 g_assert_not_reached();
96 }
97
98 n->ti_seq = 0;
99 n->ti_ack = 0;
100 n->ti_x2 = 0;
101 n->ti_off = 5;
102 n->ti_flags = 0;
103 n->ti_win = 0;
104 n->ti_sum = 0;
105 n->ti_urp = 0;
106 }
107
108 /*
109 * Send a single message to the TCP at address specified by
110 * the given TCP/IP header. If m == 0, then we make a copy
111 * of the tcpiphdr at ti and send directly to the addressed host.
112 * This is used to force keep alive messages out using the TCP
113 * template for a connection tp->t_template. If flags are given
114 * then we send a message back to the TCP which originated the
115 * segment ti, and discard the mbuf containing it and any other
116 * attached mbufs.
117 *
118 * In any case the ack and sequence number of the transmitted
119 * segment are as specified by the parameters.
120 */
121 void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
122 tcp_seq ack, tcp_seq seq, int flags, unsigned short af)
123 {
124 register int tlen;
125 int win = 0;
126
127 DEBUG_CALL("tcp_respond");
128 DEBUG_ARG("tp = %p", tp);
129 DEBUG_ARG("ti = %p", ti);
130 DEBUG_ARG("m = %p", m);
131 DEBUG_ARG("ack = %u", ack);
132 DEBUG_ARG("seq = %u", seq);
133 DEBUG_ARG("flags = %x", flags);
134
135 if (tp)
136 win = sbspace(&tp->t_socket->so_rcv);
137 if (m == NULL) {
138 if (!tp || (m = m_get(tp->t_socket->slirp)) == NULL)
139 return;
140 tlen = 0;
141 m->m_data += IF_MAXLINKHDR;
142 *mtod(m, struct tcpiphdr *) = *ti;
143 ti = mtod(m, struct tcpiphdr *);
144 switch (af) {
145 case AF_INET:
146 ti->ti.ti_i4.ih_x1 = 0;
147 break;
148 case AF_INET6:
149 ti->ti.ti_i6.ih_x1 = 0;
150 break;
151 default:
152 g_assert_not_reached();
153 }
154 flags = TH_ACK;
155 } else {
156 /*
157 * ti points into m so the next line is just making
158 * the mbuf point to ti
159 */
160 m->m_data = (char *)ti;
161
162 m->m_len = sizeof(struct tcpiphdr);
163 tlen = 0;
164 #define xchg(a, b, type) \
165 { \
166 type t; \
167 t = a; \
168 a = b; \
169 b = t; \
170 }
171 switch (af) {
172 case AF_INET:
173 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
174 xchg(ti->ti_dport, ti->ti_sport, uint16_t);
175 break;
176 case AF_INET6:
177 xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
178 xchg(ti->ti_dport, ti->ti_sport, uint16_t);
179 break;
180 default:
181 g_assert_not_reached();
182 }
183 #undef xchg
184 }
185 ti->ti_len = htons((uint16_t)(sizeof(struct tcphdr) + tlen));
186 tlen += sizeof(struct tcpiphdr);
187 m->m_len = tlen;
188
189 ti->ti_mbuf = NULL;
190 ti->ti_x0 = 0;
191 ti->ti_seq = htonl(seq);
192 ti->ti_ack = htonl(ack);
193 ti->ti_x2 = 0;
194 ti->ti_off = sizeof(struct tcphdr) >> 2;
195 ti->ti_flags = flags;
196 if (tp)
197 ti->ti_win = htons((uint16_t)(win >> tp->rcv_scale));
198 else
199 ti->ti_win = htons((uint16_t)win);
200 ti->ti_urp = 0;
201 ti->ti_sum = 0;
202 ti->ti_sum = cksum(m, tlen);
203
204 struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
205 struct ip *ip;
206 struct ip6 *ip6;
207
208 switch (af) {
209 case AF_INET:
210 m->m_data +=
211 sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
212 m->m_len -=
213 sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip);
214 ip = mtod(m, struct ip *);
215 ip->ip_len = m->m_len;
216 ip->ip_dst = tcpiph_save.ti_dst;
217 ip->ip_src = tcpiph_save.ti_src;
218 ip->ip_p = tcpiph_save.ti_pr;
219
220 if (flags & TH_RST) {
221 ip->ip_ttl = MAXTTL;
222 } else {
223 ip->ip_ttl = IPDEFTTL;
224 }
225
226 ip_output(NULL, m);
227 break;
228
229 case AF_INET6:
230 m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr) -
231 sizeof(struct ip6);
232 m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr) -
233 sizeof(struct ip6);
234 ip6 = mtod(m, struct ip6 *);
235 ip6->ip_pl = tcpiph_save.ti_len;
236 ip6->ip_dst = tcpiph_save.ti_dst6;
237 ip6->ip_src = tcpiph_save.ti_src6;
238 ip6->ip_nh = tcpiph_save.ti_nh6;
239
240 ip6_output(NULL, m, 0);
241 break;
242
243 default:
244 g_assert_not_reached();
245 }
246 }
247
248 /*
249 * Create a new TCP control block, making an
250 * empty reassembly queue and hooking it to the argument
251 * protocol control block.
252 */
253 struct tcpcb *tcp_newtcpcb(struct socket *so)
254 {
255 register struct tcpcb *tp;
256
257 tp = (struct tcpcb *)malloc(sizeof(*tp));
258 if (tp == NULL)
259 return ((struct tcpcb *)0);
260
261 memset((char *)tp, 0, sizeof(struct tcpcb));
262 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
263 /*
264 * 40: length of IPv4 header (20) + TCP header (20)
265 * 60: length of IPv6 header (40) + TCP header (20)
266 */
267 tp->t_maxseg =
268 MIN(so->slirp->if_mtu - ((so->so_ffamily == AF_INET) ? 40 : 60),
269 TCP_MAXSEG_MAX);
270
271 tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE | TF_REQ_TSTMP) : 0;
272 tp->t_socket = so;
273
274 /*
275 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
276 * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
277 * reasonable initial retransmit time.
278 */
279 tp->t_srtt = TCPTV_SRTTBASE;
280 tp->t_rttvar = TCPTV_SRTTDFLT << 2;
281 tp->t_rttmin = TCPTV_MIN;
282
283 TCPT_RANGESET(tp->t_rxtcur,
284 ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
285 TCPTV_MIN, TCPTV_REXMTMAX);
286
287 tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
288 tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
289 tp->t_state = TCPS_CLOSED;
290
291 so->so_tcpcb = tp;
292
293 return (tp);
294 }
295
296 /*
297 * Drop a TCP connection, reporting
298 * the specified error. If connection is synchronized,
299 * then send a RST to peer.
300 */
301 struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
302 {
303 DEBUG_CALL("tcp_drop");
304 DEBUG_ARG("tp = %p", tp);
305 DEBUG_ARG("errno = %d", errno);
306
307 if (TCPS_HAVERCVDSYN(tp->t_state)) {
308 tp->t_state = TCPS_CLOSED;
309 (void)tcp_output(tp);
310 }
311 return (tcp_close(tp));
312 }
313
314 /*
315 * Close a TCP control block:
316 * discard all space held by the tcp
317 * discard internet protocol block
318 * wake up any sleepers
319 */
320 struct tcpcb *tcp_close(struct tcpcb *tp)
321 {
322 register struct tcpiphdr *t;
323 struct socket *so = tp->t_socket;
324 Slirp *slirp = so->slirp;
325 register struct mbuf *m;
326
327 DEBUG_CALL("tcp_close");
328 DEBUG_ARG("tp = %p", tp);
329
330 /* free the reassembly queue, if any */
331 t = tcpfrag_list_first(tp);
332 while (!tcpfrag_list_end(t, tp)) {
333 t = tcpiphdr_next(t);
334 m = tcpiphdr_prev(t)->ti_mbuf;
335 remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
336 m_free(m);
337 }
338 free(tp);
339 so->so_tcpcb = NULL;
340 /* clobber input socket cache if we're closing the cached connection */
341 if (so == slirp->tcp_last_so)
342 slirp->tcp_last_so = &slirp->tcb;
343 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
344 closesocket(so->s);
345 sbfree(&so->so_rcv);
346 sbfree(&so->so_snd);
347 sofree(so);
348 return ((struct tcpcb *)0);
349 }
350
351 /*
352 * TCP protocol interface to socket abstraction.
353 */
354
355 /*
356 * User issued close, and wish to trail through shutdown states:
357 * if never received SYN, just forget it. If got a SYN from peer,
358 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
359 * If already got a FIN from peer, then almost done; go to LAST_ACK
360 * state. In all other cases, have already sent FIN to peer (e.g.
361 * after PRU_SHUTDOWN), and just have to play tedious game waiting
362 * for peer to send FIN or not respond to keep-alives, etc.
363 * We can let the user exit from the close as soon as the FIN is acked.
364 */
365 void tcp_sockclosed(struct tcpcb *tp)
366 {
367 DEBUG_CALL("tcp_sockclosed");
368 DEBUG_ARG("tp = %p", tp);
369
370 if (!tp) {
371 return;
372 }
373
374 switch (tp->t_state) {
375 case TCPS_CLOSED:
376 case TCPS_LISTEN:
377 case TCPS_SYN_SENT:
378 tp->t_state = TCPS_CLOSED;
379 tp = tcp_close(tp);
380 break;
381
382 case TCPS_SYN_RECEIVED:
383 case TCPS_ESTABLISHED:
384 tp->t_state = TCPS_FIN_WAIT_1;
385 break;
386
387 case TCPS_CLOSE_WAIT:
388 tp->t_state = TCPS_LAST_ACK;
389 break;
390 }
391 tcp_output(tp);
392 }
393
394 /*
395 * Connect to a host on the Internet
396 * Called by tcp_input
397 * Only do a connect, the tcp fields will be set in tcp_input
398 * return 0 if there's a result of the connect,
399 * else return -1 means we're still connecting
400 * The return value is almost always -1 since the socket is
401 * nonblocking. Connect returns after the SYN is sent, and does
402 * not wait for ACK+SYN.
403 */
404 int tcp_fconnect(struct socket *so, unsigned short af)
405 {
406 int ret = 0;
407
408 DEBUG_CALL("tcp_fconnect");
409 DEBUG_ARG("so = %p", so);
410
411 ret = so->s = slirp_socket(af, SOCK_STREAM, 0);
412 if (ret >= 0) {
413 int opt, s = so->s;
414 struct sockaddr_storage addr;
415
416 slirp_set_nonblock(s);
417 so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
418 slirp_socket_set_fast_reuse(s);
419 opt = 1;
420 setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
421 opt = 1;
422 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
423
424 addr = so->fhost.ss;
425 DEBUG_CALL(" connect()ing");
426 if (sotranslate_out(so, &addr) < 0) {
427 return -1;
428 }
429
430 /* We don't care what port we get */
431 ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr));
432
433 /*
434 * If it's not in progress, it failed, so we just return 0,
435 * without clearing SS_NOFDREF
436 */
437 soisfconnecting(so);
438 }
439
440 return (ret);
441 }
442
443 /*
444 * Accept the socket and connect to the local-host
445 *
446 * We have a problem. The correct thing to do would be
447 * to first connect to the local-host, and only if the
448 * connection is accepted, then do an accept() here.
449 * But, a) we need to know who's trying to connect
450 * to the socket to be able to SYN the local-host, and
451 * b) we are already connected to the foreign host by
452 * the time it gets to accept(), so... We simply accept
453 * here and SYN the local-host.
454 */
455 void tcp_connect(struct socket *inso)
456 {
457 Slirp *slirp = inso->slirp;
458 struct socket *so;
459 struct sockaddr_storage addr;
460 socklen_t addrlen = sizeof(struct sockaddr_storage);
461 struct tcpcb *tp;
462 int s, opt;
463
464 DEBUG_CALL("tcp_connect");
465 DEBUG_ARG("inso = %p", inso);
466
467 /*
468 * If it's an SS_ACCEPTONCE socket, no need to socreate()
469 * another socket, just use the accept() socket.
470 */
471 if (inso->so_state & SS_FACCEPTONCE) {
472 /* FACCEPTONCE already have a tcpcb */
473 so = inso;
474 } else {
475 so = socreate(slirp);
476 if (tcp_attach(so) < 0) {
477 g_free(so); /* NOT sofree */
478 return;
479 }
480 so->lhost = inso->lhost;
481 so->so_ffamily = inso->so_ffamily;
482 }
483
484 tcp_mss(sototcpcb(so), 0);
485
486 s = accept(inso->s, (struct sockaddr *)&addr, &addrlen);
487 if (s < 0) {
488 tcp_close(sototcpcb(so)); /* This will sofree() as well */
489 return;
490 }
491 slirp_set_nonblock(s);
492 so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
493 slirp_socket_set_fast_reuse(s);
494 opt = 1;
495 setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
496 slirp_socket_set_nodelay(s);
497
498 so->fhost.ss = addr;
499 sotranslate_accept(so);
500
501 /* Close the accept() socket, set right state */
502 if (inso->so_state & SS_FACCEPTONCE) {
503 /* If we only accept once, close the accept() socket */
504 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
505 closesocket(so->s);
506
507 /* Don't select it yet, even though we have an FD */
508 /* if it's not FACCEPTONCE, it's already NOFDREF */
509 so->so_state = SS_NOFDREF;
510 }
511 so->s = s;
512 so->so_state |= SS_INCOMING;
513
514 so->so_iptos = tcp_tos(so);
515 tp = sototcpcb(so);
516
517 tcp_template(tp);
518
519 tp->t_state = TCPS_SYN_SENT;
520 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
521 tp->iss = slirp->tcp_iss;
522 slirp->tcp_iss += TCP_ISSINCR / 2;
523 tcp_sendseqinit(tp);
524 tcp_output(tp);
525 }
526
527 /*
528 * Attach a TCPCB to a socket.
529 */
530 int tcp_attach(struct socket *so)
531 {
532 if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
533 return -1;
534
535 insque(so, &so->slirp->tcb);
536
537 return 0;
538 }
539
540 /*
541 * Set the socket's type of service field
542 */
543 static const struct tos_t tcptos[] = {
544 { 0, 20, IPTOS_THROUGHPUT, 0 }, /* ftp data */
545 { 21, 21, IPTOS_LOWDELAY, EMU_FTP }, /* ftp control */
546 { 0, 23, IPTOS_LOWDELAY, 0 }, /* telnet */
547 { 0, 80, IPTOS_THROUGHPUT, 0 }, /* WWW */
548 { 0, 513, IPTOS_LOWDELAY, EMU_RLOGIN | EMU_NOCONNECT }, /* rlogin */
549 { 0, 544, IPTOS_LOWDELAY, EMU_KSH }, /* kshell */
550 { 0, 543, IPTOS_LOWDELAY, 0 }, /* klogin */
551 { 0, 6667, IPTOS_THROUGHPUT, EMU_IRC }, /* IRC */
552 { 0, 6668, IPTOS_THROUGHPUT, EMU_IRC }, /* IRC undernet */
553 { 0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
554 { 0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
555 { 0, 0, 0, 0 }
556 };
557
558 /*
559 * Return TOS according to the above table
560 */
561 uint8_t tcp_tos(struct socket *so)
562 {
563 int i = 0;
564
565 while (tcptos[i].tos) {
566 if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
567 (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
568 if (so->slirp->enable_emu)
569 so->so_emu = tcptos[i].emu;
570 return tcptos[i].tos;
571 }
572 i++;
573 }
574 return 0;
575 }
576
577 /*
578 * Emulate programs that try and connect to us
579 * This includes ftp (the data connection is
580 * initiated by the server) and IRC (DCC CHAT and
581 * DCC SEND) for now
582 *
583 * NOTE: It's possible to crash SLiRP by sending it
584 * unstandard strings to emulate... if this is a problem,
585 * more checks are needed here
586 *
587 * XXX Assumes the whole command came in one packet
588 *
589 * XXX Some ftp clients will have their TOS set to
590 * LOWDELAY and so Nagel will kick in. Because of this,
591 * we'll get the first letter, followed by the rest, so
592 * we simply scan for ORT instead of PORT...
593 * DCC doesn't have this problem because there's other stuff
594 * in the packet before the DCC command.
595 *
596 * Return 1 if the mbuf m is still valid and should be
597 * sbappend()ed
598 *
599 * NOTE: if you return 0 you MUST m_free() the mbuf!
600 */
601 int tcp_emu(struct socket *so, struct mbuf *m)
602 {
603 Slirp *slirp = so->slirp;
604 unsigned n1, n2, n3, n4, n5, n6;
605 char buff[257];
606 uint32_t laddr;
607 unsigned lport;
608 char *bptr;
609
610 DEBUG_CALL("tcp_emu");
611 DEBUG_ARG("so = %p", so);
612 DEBUG_ARG("m = %p", m);
613
614 switch (so->so_emu) {
615 int x, i;
616
617 /* TODO: IPv6 */
618 case EMU_IDENT:
619 /*
620 * Identification protocol as per rfc-1413
621 */
622
623 {
624 struct socket *tmpso;
625 struct sockaddr_in addr;
626 socklen_t addrlen = sizeof(struct sockaddr_in);
627 char *eol = g_strstr_len(m->m_data, m->m_len, "\r\n");
628
629 if (!eol) {
630 return 1;
631 }
632
633 *eol = '\0';
634 if (sscanf(m->m_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
635 HTONS(n1);
636 HTONS(n2);
637 /* n2 is the one on our host */
638 for (tmpso = slirp->tcb.so_next; tmpso != &slirp->tcb;
639 tmpso = tmpso->so_next) {
640 if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
641 tmpso->so_lport == n2 &&
642 tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
643 tmpso->so_fport == n1) {
644 if (getsockname(tmpso->s, (struct sockaddr *)&addr,
645 &addrlen) == 0)
646 n2 = addr.sin_port;
647 break;
648 }
649 }
650 NTOHS(n1);
651 NTOHS(n2);
652 m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1);
653 m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
654 assert(m->m_len < M_ROOM(m));
655 } else {
656 *eol = '\r';
657 }
658
659 return 1;
660 }
661
662 case EMU_FTP: /* ftp */
663 m_inc(m, m->m_len + 1);
664 *(m->m_data + m->m_len) = 0; /* NUL terminate for strstr */
665 if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
666 /*
667 * Need to emulate the PORT command
668 */
669 x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]", &n1, &n2,
670 &n3, &n4, &n5, &n6, buff);
671 if (x < 6)
672 return 1;
673
674 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
675 lport = htons((n5 << 8) | (n6));
676
677 if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr, lport,
678 SS_FACCEPTONCE)) == NULL) {
679 return 1;
680 }
681 n6 = ntohs(so->so_fport);
682
683 n5 = (n6 >> 8) & 0xff;
684 n6 &= 0xff;
685
686 laddr = ntohl(so->so_faddr.s_addr);
687
688 n1 = ((laddr >> 24) & 0xff);
689 n2 = ((laddr >> 16) & 0xff);
690 n3 = ((laddr >> 8) & 0xff);
691 n4 = (laddr & 0xff);
692
693 m->m_len = bptr - m->m_data; /* Adjust length */
694 m->m_len += snprintf(bptr, m->m_size - m->m_len,
695 "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4,
696 n5, n6, x == 7 ? buff : "");
697 return 1;
698 } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
699 /*
700 * Need to emulate the PASV response
701 */
702 x = sscanf(
703 bptr,
704 "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
705 &n1, &n2, &n3, &n4, &n5, &n6, buff);
706 if (x < 6)
707 return 1;
708
709 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
710 lport = htons((n5 << 8) | (n6));
711
712 if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr, lport,
713 SS_FACCEPTONCE)) == NULL) {
714 return 1;
715 }
716 n6 = ntohs(so->so_fport);
717
718 n5 = (n6 >> 8) & 0xff;
719 n6 &= 0xff;
720
721 laddr = ntohl(so->so_faddr.s_addr);
722
723 n1 = ((laddr >> 24) & 0xff);
724 n2 = ((laddr >> 16) & 0xff);
725 n3 = ((laddr >> 8) & 0xff);
726 n4 = (laddr & 0xff);
727
728 m->m_len = bptr - m->m_data; /* Adjust length */
729 m->m_len +=
730 snprintf(bptr, m->m_size - m->m_len,
731 "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
732 n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
733
734 return 1;
735 }
736
737 return 1;
738
739 case EMU_KSH:
740 /*
741 * The kshell (Kerberos rsh) and shell services both pass
742 * a local port port number to carry signals to the server
743 * and stderr to the client. It is passed at the beginning
744 * of the connection as a NUL-terminated decimal ASCII string.
745 */
746 so->so_emu = 0;
747 for (lport = 0, i = 0; i < m->m_len - 1; ++i) {
748 if (m->m_data[i] < '0' || m->m_data[i] > '9')
749 return 1; /* invalid number */
750 lport *= 10;
751 lport += m->m_data[i] - '0';
752 }
753 if (m->m_data[m->m_len - 1] == '\0' && lport != 0 &&
754 (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
755 htons(lport), SS_FACCEPTONCE)) != NULL)
756 m->m_len =
757 snprintf(m->m_data, m->m_size, "%d", ntohs(so->so_fport)) + 1;
758 return 1;
759
760 case EMU_IRC:
761 /*
762 * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
763 */
764 m_inc(m, m->m_len + 1);
765 *(m->m_data + m->m_len) = 0; /* NULL terminate the string for strstr */
766 if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
767 return 1;
768
769 /* The %256s is for the broken mIRC */
770 if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
771 if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
772 htons(lport), SS_FACCEPTONCE)) == NULL) {
773 return 1;
774 }
775 m->m_len = bptr - m->m_data; /* Adjust length */
776 m->m_len += snprintf(bptr, m->m_size, "DCC CHAT chat %lu %u%c\n",
777 (unsigned long)ntohl(so->so_faddr.s_addr),
778 ntohs(so->so_fport), 1);
779 } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport,
780 &n1) == 4) {
781 if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
782 htons(lport), SS_FACCEPTONCE)) == NULL) {
783 return 1;
784 }
785 m->m_len = bptr - m->m_data; /* Adjust length */
786 m->m_len +=
787 snprintf(bptr, m->m_size, "DCC SEND %s %lu %u %u%c\n", buff,
788 (unsigned long)ntohl(so->so_faddr.s_addr),
789 ntohs(so->so_fport), n1, 1);
790 } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport,
791 &n1) == 4) {
792 if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
793 htons(lport), SS_FACCEPTONCE)) == NULL) {
794 return 1;
795 }
796 m->m_len = bptr - m->m_data; /* Adjust length */
797 m->m_len +=
798 snprintf(bptr, m->m_size, "DCC MOVE %s %lu %u %u%c\n", buff,
799 (unsigned long)ntohl(so->so_faddr.s_addr),
800 ntohs(so->so_fport), n1, 1);
801 }
802 return 1;
803
804 case EMU_REALAUDIO:
805 /*
806 * RealAudio emulation - JP. We must try to parse the incoming
807 * data and try to find the two characters that contain the
808 * port number. Then we redirect an udp port and replace the
809 * number with the real port we got.
810 *
811 * The 1.0 beta versions of the player are not supported
812 * any more.
813 *
814 * A typical packet for player version 1.0 (release version):
815 *
816 * 0000:50 4E 41 00 05
817 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P
818 * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
819 * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
820 * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
821 *
822 * Now the port number 0x1BD7 is found at offset 0x04 of the
823 * Now the port number 0x1BD7 is found at offset 0x04 of the
824 * second packet. This time we received five bytes first and
825 * then the rest. You never know how many bytes you get.
826 *
827 * A typical packet for player version 2.0 (beta):
828 *
829 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA.............
830 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0
831 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
832 * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
833 * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
834 *
835 * Port number 0x1BC1 is found at offset 0x0d.
836 *
837 * This is just a horrible switch statement. Variable ra tells
838 * us where we're going.
839 */
840
841 bptr = m->m_data;
842 while (bptr < m->m_data + m->m_len) {
843 uint16_t p;
844 static int ra = 0;
845 char ra_tbl[4];
846
847 ra_tbl[0] = 0x50;
848 ra_tbl[1] = 0x4e;
849 ra_tbl[2] = 0x41;
850 ra_tbl[3] = 0;
851
852 switch (ra) {
853 case 0:
854 case 2:
855 case 3:
856 if (*bptr++ != ra_tbl[ra]) {
857 ra = 0;
858 continue;
859 }
860 break;
861
862 case 1:
863 /*
864 * We may get 0x50 several times, ignore them
865 */
866 if (*bptr == 0x50) {
867 ra = 1;
868 bptr++;
869 continue;
870 } else if (*bptr++ != ra_tbl[ra]) {
871 ra = 0;
872 continue;
873 }
874 break;
875
876 case 4:
877 /*
878 * skip version number
879 */
880 bptr++;
881 break;
882
883 case 5:
884 /*
885 * The difference between versions 1.0 and
886 * 2.0 is here. For future versions of
887 * the player this may need to be modified.
888 */
889 if (*(bptr + 1) == 0x02)
890 bptr += 8;
891 else
892 bptr += 4;
893 break;
894
895 case 6:
896 /* This is the field containing the port
897 * number that RA-player is listening to.
898 */
899 lport = (((uint8_t *)bptr)[0] << 8) + ((uint8_t *)bptr)[1];
900 if (lport < 6970)
901 lport += 256; /* don't know why */
902 if (lport < 6970 || lport > 7170)
903 return 1; /* failed */
904
905 /* try to get udp port between 6970 - 7170 */
906 for (p = 6970; p < 7071; p++) {
907 if (udp_listen(slirp, INADDR_ANY, htons(p),
908 so->so_laddr.s_addr, htons(lport),
909 SS_FACCEPTONCE)) {
910 break;
911 }
912 }
913 if (p == 7071)
914 p = 0;
915 *(uint8_t *)bptr++ = (p >> 8) & 0xff;
916 *(uint8_t *)bptr = p & 0xff;
917 ra = 0;
918 return 1; /* port redirected, we're done */
919 break;
920
921 default:
922 ra = 0;
923 }
924 ra++;
925 }
926 return 1;
927
928 default:
929 /* Ooops, not emulated, won't call tcp_emu again */
930 so->so_emu = 0;
931 return 1;
932 }
933 }
934
935 /*
936 * Do misc. config of SLiRP while its running.
937 * Return 0 if this connections is to be closed, 1 otherwise,
938 * return 2 if this is a command-line connection
939 */
940 int tcp_ctl(struct socket *so)
941 {
942 Slirp *slirp = so->slirp;
943 struct sbuf *sb = &so->so_snd;
944 struct gfwd_list *ex_ptr;
945
946 DEBUG_CALL("tcp_ctl");
947 DEBUG_ARG("so = %p", so);
948
949 /* TODO: IPv6 */
950 if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
951 /* Check if it's pty_exec */
952 for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
953 if (ex_ptr->ex_fport == so->so_fport &&
954 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
955 if (ex_ptr->write_cb) {
956 so->s = -1;
957 so->guestfwd = ex_ptr;
958 return 1;
959 }
960 DEBUG_MISC(" executing %s", ex_ptr->ex_exec);
961 return fork_exec(so, ex_ptr->ex_exec);
962 }
963 }
964 }
965 sb->sb_cc =
966 snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
967 "Error: No application configured.\r\n");
968 sb->sb_wptr += sb->sb_cc;
969 return 0;
970 }
+0
-286
vendor/libslirp/src/tcp_timer.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93
30 * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
31 */
32
33 #include "slirp.h"
34
35 static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
36
37 /*
38 * Fast timeout routine for processing delayed acks
39 */
40 void tcp_fasttimo(Slirp *slirp)
41 {
42 register struct socket *so;
43 register struct tcpcb *tp;
44
45 DEBUG_CALL("tcp_fasttimo");
46
47 so = slirp->tcb.so_next;
48 if (so)
49 for (; so != &slirp->tcb; so = so->so_next)
50 if ((tp = (struct tcpcb *)so->so_tcpcb) &&
51 (tp->t_flags & TF_DELACK)) {
52 tp->t_flags &= ~TF_DELACK;
53 tp->t_flags |= TF_ACKNOW;
54 (void)tcp_output(tp);
55 }
56 }
57
58 /*
59 * Tcp protocol timeout routine called every 500 ms.
60 * Updates the timers in all active tcb's and
61 * causes finite state machine actions if timers expire.
62 */
63 void tcp_slowtimo(Slirp *slirp)
64 {
65 register struct socket *ip, *ipnxt;
66 register struct tcpcb *tp;
67 register int i;
68
69 DEBUG_CALL("tcp_slowtimo");
70
71 /*
72 * Search through tcb's and update active timers.
73 */
74 ip = slirp->tcb.so_next;
75 if (ip == NULL) {
76 return;
77 }
78 for (; ip != &slirp->tcb; ip = ipnxt) {
79 ipnxt = ip->so_next;
80 tp = sototcpcb(ip);
81 if (tp == NULL) {
82 continue;
83 }
84 for (i = 0; i < TCPT_NTIMERS; i++) {
85 if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
86 tcp_timers(tp, i);
87 if (ipnxt->so_prev != ip)
88 goto tpgone;
89 }
90 }
91 tp->t_idle++;
92 if (tp->t_rtt)
93 tp->t_rtt++;
94 tpgone:;
95 }
96 slirp->tcp_iss += TCP_ISSINCR / PR_SLOWHZ; /* increment iss */
97 slirp->tcp_now++; /* for timestamps */
98 }
99
100 /*
101 * Cancel all timers for TCP tp.
102 */
103 void tcp_canceltimers(struct tcpcb *tp)
104 {
105 register int i;
106
107 for (i = 0; i < TCPT_NTIMERS; i++)
108 tp->t_timer[i] = 0;
109 }
110
111 const int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64,
112 64, 64, 64, 64, 64, 64 };
113
114 /*
115 * TCP timer processing.
116 */
117 static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer)
118 {
119 register int rexmt;
120
121 DEBUG_CALL("tcp_timers");
122
123 switch (timer) {
124 /*
125 * 2 MSL timeout in shutdown went off. If we're closed but
126 * still waiting for peer to close and connection has been idle
127 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
128 * control block. Otherwise, check again in a bit.
129 */
130 case TCPT_2MSL:
131 if (tp->t_state != TCPS_TIME_WAIT && tp->t_idle <= TCP_MAXIDLE)
132 tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
133 else
134 tp = tcp_close(tp);
135 break;
136
137 /*
138 * Retransmission timer went off. Message has not
139 * been acked within retransmit interval. Back off
140 * to a longer retransmit interval and retransmit one segment.
141 */
142 case TCPT_REXMT:
143
144 /*
145 * XXXXX If a packet has timed out, then remove all the queued
146 * packets for that session.
147 */
148
149 if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
150 /*
151 * This is a hack to suit our terminal server here at the uni of
152 * canberra since they have trouble with zeroes... It usually lets
153 * them through unharmed, but under some conditions, it'll eat the
154 * zeros. If we keep retransmitting it, it'll keep eating the
155 * zeroes, so we keep retransmitting, and eventually the connection
156 * dies... (this only happens on incoming data)
157 *
158 * So, if we were gonna drop the connection from too many
159 * retransmits, don't... instead halve the t_maxseg, which might
160 * break up the NULLs and let them through
161 *
162 * *sigh*
163 */
164
165 tp->t_maxseg >>= 1;
166 if (tp->t_maxseg < 32) {
167 /*
168 * We tried our best, now the connection must die!
169 */
170 tp->t_rxtshift = TCP_MAXRXTSHIFT;
171 tp = tcp_drop(tp, tp->t_softerror);
172 /* tp->t_softerror : ETIMEDOUT); */ /* XXX */
173 return (tp); /* XXX */
174 }
175
176 /*
177 * Set rxtshift to 6, which is still at the maximum
178 * backoff time
179 */
180 tp->t_rxtshift = 6;
181 }
182 rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
183 TCPT_RANGESET(tp->t_rxtcur, rexmt, (short)tp->t_rttmin,
184 TCPTV_REXMTMAX); /* XXX */
185 tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
186 /*
187 * If losing, let the lower level know and try for
188 * a better route. Also, if we backed off this far,
189 * our srtt estimate is probably bogus. Clobber it
190 * so we'll take the next rtt measurement as our srtt;
191 * move the current srtt into rttvar to keep the current
192 * retransmit times until then.
193 */
194 if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
195 tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
196 tp->t_srtt = 0;
197 }
198 tp->snd_nxt = tp->snd_una;
199 /*
200 * If timing a segment in this window, stop the timer.
201 */
202 tp->t_rtt = 0;
203 /*
204 * Close the congestion window down to one segment
205 * (we'll open it by one segment for each ack we get).
206 * Since we probably have a window's worth of unacked
207 * data accumulated, this "slow start" keeps us from
208 * dumping all that data as back-to-back packets (which
209 * might overwhelm an intermediate gateway).
210 *
211 * There are two phases to the opening: Initially we
212 * open by one mss on each ack. This makes the window
213 * size increase exponentially with time. If the
214 * window is larger than the path can handle, this
215 * exponential growth results in dropped packet(s)
216 * almost immediately. To get more time between
217 * drops but still "push" the network to take advantage
218 * of improving conditions, we switch from exponential
219 * to linear window opening at some threshold size.
220 * For a threshold, we use half the current window
221 * size, truncated to a multiple of the mss.
222 *
223 * (the minimum cwnd that will give us exponential
224 * growth is 2 mss. We don't allow the threshold
225 * to go below this.)
226 */
227 {
228 unsigned win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
229 if (win < 2)
230 win = 2;
231 tp->snd_cwnd = tp->t_maxseg;
232 tp->snd_ssthresh = win * tp->t_maxseg;
233 tp->t_dupacks = 0;
234 }
235 (void)tcp_output(tp);
236 break;
237
238 /*
239 * Persistence timer into zero window.
240 * Force a byte to be output, if possible.
241 */
242 case TCPT_PERSIST:
243 tcp_setpersist(tp);
244 tp->t_force = 1;
245 (void)tcp_output(tp);
246 tp->t_force = 0;
247 break;
248
249 /*
250 * Keep-alive timer went off; send something
251 * or drop connection if idle for too long.
252 */
253 case TCPT_KEEP:
254 if (tp->t_state < TCPS_ESTABLISHED)
255 goto dropit;
256
257 if (slirp_do_keepalive && tp->t_state <= TCPS_CLOSE_WAIT) {
258 if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
259 goto dropit;
260 /*
261 * Send a packet designed to force a response
262 * if the peer is up and reachable:
263 * either an ACK if the connection is still alive,
264 * or an RST if the peer has closed the connection
265 * due to timeout or reboot.
266 * Using sequence number tp->snd_una-1
267 * causes the transmitted zero-length segment
268 * to lie outside the receive window;
269 * by the protocol spec, this requires the
270 * correspondent TCP to respond.
271 */
272 tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt,
273 tp->snd_una - 1, 0, tp->t_socket->so_ffamily);
274 tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
275 } else
276 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
277 break;
278
279 dropit:
280 tp = tcp_drop(tp, 0);
281 break;
282 }
283
284 return (tp);
285 }
+0
-130
vendor/libslirp/src/tcp_timer.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
30 * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp
31 */
32
33 #ifndef TCP_TIMER_H
34 #define TCP_TIMER_H
35
36 /*
37 * Definitions of the TCP timers. These timers are counted
38 * down PR_SLOWHZ times a second.
39 */
40 #define TCPT_NTIMERS 4
41
42 #define TCPT_REXMT 0 /* retransmit */
43 #define TCPT_PERSIST 1 /* retransmit persistence */
44 #define TCPT_KEEP 2 /* keep alive */
45 #define TCPT_2MSL 3 /* 2*msl quiet time timer */
46
47 /*
48 * The TCPT_REXMT timer is used to force retransmissions.
49 * The TCP has the TCPT_REXMT timer set whenever segments
50 * have been sent for which ACKs are expected but not yet
51 * received. If an ACK is received which advances tp->snd_una,
52 * then the retransmit timer is cleared (if there are no more
53 * outstanding segments) or reset to the base value (if there
54 * are more ACKs expected). Whenever the retransmit timer goes off,
55 * we retransmit one unacknowledged segment, and do a backoff
56 * on the retransmit timer.
57 *
58 * The TCPT_PERSIST timer is used to keep window size information
59 * flowing even if the window goes shut. If all previous transmissions
60 * have been acknowledged (so that there are no retransmissions in progress),
61 * and the window is too small to bother sending anything, then we start
62 * the TCPT_PERSIST timer. When it expires, if the window is nonzero,
63 * we go to transmit state. Otherwise, at intervals send a single byte
64 * into the peer's window to force him to update our window information.
65 * We do this at most as often as TCPT_PERSMIN time intervals,
66 * but no more frequently than the current estimate of round-trip
67 * packet time. The TCPT_PERSIST timer is cleared whenever we receive
68 * a window update from the peer.
69 *
70 * The TCPT_KEEP timer is used to keep connections alive. If an
71 * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
72 * but not yet established, then we drop the connection. Once the connection
73 * is established, if the connection is idle for TCPTV_KEEP_IDLE time
74 * (and keepalives have been enabled on the socket), we begin to probe
75 * the connection. We force the peer to send us a segment by sending:
76 * <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
77 * This segment is (deliberately) outside the window, and should elicit
78 * an ack segment in response from the peer. If, despite the TCPT_KEEP
79 * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
80 * amount of time probing, then we drop the connection.
81 */
82
83 /*
84 * Time constants.
85 */
86 #define TCPTV_MSL (5 * PR_SLOWHZ) /* max seg lifetime (hah!) */
87
88 #define TCPTV_SRTTBASE \
89 0 /* base roundtrip time; \
90 if 0, no idea yet */
91 #define TCPTV_SRTTDFLT (3 * PR_SLOWHZ) /* assumed RTT if no info */
92
93 #define TCPTV_PERSMIN (5 * PR_SLOWHZ) /* retransmit persistence */
94 #define TCPTV_PERSMAX (60 * PR_SLOWHZ) /* maximum persist interval */
95
96 #define TCPTV_KEEP_INIT (75 * PR_SLOWHZ) /* initial connect keep alive */
97 #define TCPTV_KEEP_IDLE (120 * 60 * PR_SLOWHZ) /* dflt time before probing */
98 #define TCPTV_KEEPINTVL (75 * PR_SLOWHZ) /* default probe interval */
99 #define TCPTV_KEEPCNT 8 /* max probes before drop */
100
101 #define TCPTV_MIN (1 * PR_SLOWHZ) /* minimum allowable value */
102 #define TCPTV_REXMTMAX (12 * PR_SLOWHZ) /* max allowable REXMT value */
103
104 #define TCP_LINGERTIME 120 /* linger at most 2 minutes */
105
106 #define TCP_MAXRXTSHIFT 12 /* maximum retransmits */
107
108
109 /*
110 * Force a time value to be in a certain range.
111 */
112 #define TCPT_RANGESET(tv, value, tvmin, tvmax) \
113 { \
114 (tv) = (value); \
115 if ((tv) < (tvmin)) \
116 (tv) = (tvmin); \
117 else if ((tv) > (tvmax)) \
118 (tv) = (tvmax); \
119 }
120
121 extern const int tcp_backoff[];
122
123 struct tcpcb;
124
125 void tcp_fasttimo(Slirp *);
126 void tcp_slowtimo(Slirp *);
127 void tcp_canceltimers(struct tcpcb *);
128
129 #endif
+0
-161
vendor/libslirp/src/tcp_var.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94
30 * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
31 */
32
33 #ifndef TCP_VAR_H
34 #define TCP_VAR_H
35
36 #include "tcpip.h"
37 #include "tcp_timer.h"
38
39 /*
40 * Tcp control block, one per tcp; fields:
41 */
42 struct tcpcb {
43 struct tcpiphdr *seg_next; /* sequencing queue */
44 struct tcpiphdr *seg_prev;
45 short t_state; /* state of this connection */
46 short t_timer[TCPT_NTIMERS]; /* tcp timers */
47 short t_rxtshift; /* log(2) of rexmt exp. backoff */
48 short t_rxtcur; /* current retransmit value */
49 short t_dupacks; /* consecutive dup acks recd */
50 uint16_t t_maxseg; /* maximum segment size */
51 uint8_t t_force; /* 1 if forcing out a byte */
52 uint16_t t_flags;
53 #define TF_ACKNOW 0x0001 /* ack peer immediately */
54 #define TF_DELACK 0x0002 /* ack, but try to delay it */
55 #define TF_NODELAY 0x0004 /* don't delay packets to coalesce */
56 #define TF_NOOPT 0x0008 /* don't use tcp options */
57 #define TF_SENTFIN 0x0010 /* have sent FIN */
58 #define TF_REQ_SCALE 0x0020 /* have/will request window scaling */
59 #define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */
60 #define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */
61 #define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */
62 #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */
63
64 struct tcpiphdr t_template; /* static skeletal packet for xmit */
65
66 struct socket *t_socket; /* back pointer to socket */
67 /*
68 * The following fields are used as in the protocol specification.
69 * See RFC783, Dec. 1981, page 21.
70 */
71 /* send sequence variables */
72 tcp_seq snd_una; /* send unacknowledged */
73 tcp_seq snd_nxt; /* send next */
74 tcp_seq snd_up; /* send urgent pointer */
75 tcp_seq snd_wl1; /* window update seg seq number */
76 tcp_seq snd_wl2; /* window update seg ack number */
77 tcp_seq iss; /* initial send sequence number */
78 uint32_t snd_wnd; /* send window */
79 /* receive sequence variables */
80 uint32_t rcv_wnd; /* receive window */
81 tcp_seq rcv_nxt; /* receive next */
82 tcp_seq rcv_up; /* receive urgent pointer */
83 tcp_seq irs; /* initial receive sequence number */
84 /*
85 * Additional variables for this implementation.
86 */
87 /* receive variables */
88 tcp_seq rcv_adv; /* advertised window */
89 /* retransmit variables */
90 tcp_seq snd_max; /* highest sequence number sent;
91 * used to recognize retransmits
92 */
93 /* congestion control (for slow start, source quench, retransmit after loss)
94 */
95 uint32_t snd_cwnd; /* congestion-controlled window */
96 uint32_t snd_ssthresh; /* snd_cwnd size threshold for
97 * for slow start exponential to
98 * linear switch
99 */
100 /*
101 * transmit timing stuff. See below for scale of srtt and rttvar.
102 * "Variance" is actually smoothed difference.
103 */
104 short t_idle; /* inactivity time */
105 short t_rtt; /* round trip time */
106 tcp_seq t_rtseq; /* sequence number being timed */
107 short t_srtt; /* smoothed round-trip time */
108 short t_rttvar; /* variance in round-trip time */
109 uint16_t t_rttmin; /* minimum rtt allowed */
110 uint32_t max_sndwnd; /* largest window peer has offered */
111
112 /* out-of-band data */
113 uint8_t t_oobflags; /* have some */
114 uint8_t t_iobc; /* input character */
115 #define TCPOOB_HAVEDATA 0x01
116 #define TCPOOB_HADDATA 0x02
117 short t_softerror; /* possible error not yet reported */
118
119 /* RFC 1323 variables */
120 uint8_t snd_scale; /* window scaling for send window */
121 uint8_t rcv_scale; /* window scaling for recv window */
122 uint8_t request_r_scale; /* pending window scaling */
123 uint8_t requested_s_scale;
124 uint32_t ts_recent; /* timestamp echo data */
125 uint32_t ts_recent_age; /* when last updated */
126 tcp_seq last_ack_sent;
127 };
128
129 #define sototcpcb(so) ((so)->so_tcpcb)
130
131 /*
132 * The smoothed round-trip time and estimated variance
133 * are stored as fixed point numbers scaled by the values below.
134 * For convenience, these scales are also used in smoothing the average
135 * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
136 * With these scales, srtt has 3 bits to the right of the binary point,
137 * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the
138 * binary point, and is smoothed with an ALPHA of 0.75.
139 */
140 #define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */
141 #define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */
142 #define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */
143 #define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */
144
145 /*
146 * The initial retransmission should happen at rtt + 4 * rttvar.
147 * Because of the way we do the smoothing, srtt and rttvar
148 * will each average +1/2 tick of bias. When we compute
149 * the retransmit timer, we want 1/2 tick of rounding and
150 * 1 extra tick because of +-1/2 tick uncertainty in the
151 * firing of the timer. The bias will give us exactly the
152 * 1.5 tick we need. But, because the bias is
153 * statistical, we have to test that we don't drop below
154 * the minimum feasible timer (which is 2 ticks).
155 * This macro assumes that the value of TCP_RTTVAR_SCALE
156 * is the same as the multiplier for rttvar.
157 */
158 #define TCP_REXMTVAL(tp) (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
159
160 #endif
+0
-104
vendor/libslirp/src/tcpip.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcpip.h 8.1 (Berkeley) 6/10/93
30 * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
31 */
32
33 #ifndef TCPIP_H
34 #define TCPIP_H
35
36 /*
37 * Tcp+ip header, after ip options removed.
38 */
39 struct tcpiphdr {
40 struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */
41 union {
42 struct {
43 struct in_addr ih_src; /* source internet address */
44 struct in_addr ih_dst; /* destination internet address */
45 uint8_t ih_x1; /* (unused) */
46 uint8_t ih_pr; /* protocol */
47 } ti_i4;
48 struct {
49 struct in6_addr ih_src;
50 struct in6_addr ih_dst;
51 uint8_t ih_x1;
52 uint8_t ih_nh;
53 } ti_i6;
54 } ti;
55 uint16_t ti_x0;
56 uint16_t ti_len; /* protocol length */
57 struct tcphdr ti_t; /* tcp header */
58 };
59 #define ti_mbuf ih_mbuf.mptr
60 #define ti_pr ti.ti_i4.ih_pr
61 #define ti_src ti.ti_i4.ih_src
62 #define ti_dst ti.ti_i4.ih_dst
63 #define ti_src6 ti.ti_i6.ih_src
64 #define ti_dst6 ti.ti_i6.ih_dst
65 #define ti_nh6 ti.ti_i6.ih_nh
66 #define ti_sport ti_t.th_sport
67 #define ti_dport ti_t.th_dport
68 #define ti_seq ti_t.th_seq
69 #define ti_ack ti_t.th_ack
70 #define ti_x2 ti_t.th_x2
71 #define ti_off ti_t.th_off
72 #define ti_flags ti_t.th_flags
73 #define ti_win ti_t.th_win
74 #define ti_sum ti_t.th_sum
75 #define ti_urp ti_t.th_urp
76
77 #define tcpiphdr2qlink(T) \
78 ((struct qlink *)(((char *)(T)) - sizeof(struct qlink)))
79 #define qlink2tcpiphdr(Q) \
80 ((struct tcpiphdr *)(((char *)(Q)) + sizeof(struct qlink)))
81 #define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next)
82 #define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev)
83 #define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next)
84 #define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink *)(T))
85 #define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr *)(T))
86
87 /* This is the difference between the size of a tcpiphdr structure, and the
88 * size of actual ip+tcp headers, rounded up since we need to align data. */
89 #define TCPIPHDR_DELTA \
90 (MAX(0, (sizeof(struct tcpiphdr) - sizeof(struct ip) - \
91 sizeof(struct tcphdr) + 3) & \
92 ~3))
93
94 /*
95 * Just a clean way to get to the first byte
96 * of the packet
97 */
98 struct tcpiphdr_2 {
99 struct tcpiphdr dummy;
100 char first_char;
101 };
102
103 #endif
+0
-462
vendor/libslirp/src/tftp.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * tftp.c - a simple, read-only tftp server for qemu
3 *
4 * Copyright (c) 2004 Magnus Damm <damm@opensource.se>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "slirp.h"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30
31 static inline int tftp_session_in_use(struct tftp_session *spt)
32 {
33 return (spt->slirp != NULL);
34 }
35
36 static inline void tftp_session_update(struct tftp_session *spt)
37 {
38 spt->timestamp = curtime;
39 }
40
41 static void tftp_session_terminate(struct tftp_session *spt)
42 {
43 if (spt->fd >= 0) {
44 close(spt->fd);
45 spt->fd = -1;
46 }
47 g_free(spt->filename);
48 spt->slirp = NULL;
49 }
50
51 static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
52 struct tftp_t *tp)
53 {
54 struct tftp_session *spt;
55 int k;
56
57 for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
58 spt = &slirp->tftp_sessions[k];
59
60 if (!tftp_session_in_use(spt))
61 goto found;
62
63 /* sessions time out after 5 inactive seconds */
64 if ((int)(curtime - spt->timestamp) > 5000) {
65 tftp_session_terminate(spt);
66 goto found;
67 }
68 }
69
70 return -1;
71
72 found:
73 memset(spt, 0, sizeof(*spt));
74 memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
75 spt->fd = -1;
76 spt->block_size = 512;
77 spt->client_port = tp->udp.uh_sport;
78 spt->slirp = slirp;
79
80 tftp_session_update(spt);
81
82 return k;
83 }
84
85 static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
86 struct tftp_t *tp)
87 {
88 struct tftp_session *spt;
89 int k;
90
91 for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
92 spt = &slirp->tftp_sessions[k];
93
94 if (tftp_session_in_use(spt)) {
95 if (sockaddr_equal(&spt->client_addr, srcsas)) {
96 if (spt->client_port == tp->udp.uh_sport) {
97 return k;
98 }
99 }
100 }
101 }
102
103 return -1;
104 }
105
106 static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
107 uint8_t *buf, int len)
108 {
109 int bytes_read = 0;
110
111 if (spt->fd < 0) {
112 spt->fd = open(spt->filename, O_RDONLY | O_BINARY);
113 }
114
115 if (spt->fd < 0) {
116 return -1;
117 }
118
119 if (len) {
120 lseek(spt->fd, block_nr * spt->block_size, SEEK_SET);
121
122 bytes_read = read(spt->fd, buf, len);
123 }
124
125 return bytes_read;
126 }
127
128 static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
129 struct mbuf *m)
130 {
131 struct tftp_t *tp;
132
133 memset(m->m_data, 0, m->m_size);
134
135 m->m_data += IF_MAXLINKHDR;
136 if (spt->client_addr.ss_family == AF_INET6) {
137 m->m_data += sizeof(struct ip6);
138 } else {
139 m->m_data += sizeof(struct ip);
140 }
141 tp = (void *)m->m_data;
142 m->m_data += sizeof(struct udphdr);
143
144 return tp;
145 }
146
147 static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
148 struct tftp_t *recv_tp)
149 {
150 if (spt->client_addr.ss_family == AF_INET6) {
151 struct sockaddr_in6 sa6, da6;
152
153 sa6.sin6_addr = spt->slirp->vhost_addr6;
154 sa6.sin6_port = recv_tp->udp.uh_dport;
155 da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
156 da6.sin6_port = spt->client_port;
157
158 udp6_output(NULL, m, &sa6, &da6);
159 } else {
160 struct sockaddr_in sa4, da4;
161
162 sa4.sin_addr = spt->slirp->vhost_addr;
163 sa4.sin_port = recv_tp->udp.uh_dport;
164 da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
165 da4.sin_port = spt->client_port;
166
167 udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
168 }
169 }
170
171 static int tftp_send_oack(struct tftp_session *spt, const char *keys[],
172 uint32_t values[], int nb, struct tftp_t *recv_tp)
173 {
174 struct mbuf *m;
175 struct tftp_t *tp;
176 int i, n = 0;
177
178 m = m_get(spt->slirp);
179
180 if (!m)
181 return -1;
182
183 tp = tftp_prep_mbuf_data(spt, m);
184
185 tp->tp_op = htons(TFTP_OACK);
186 for (i = 0; i < nb; i++) {
187 n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
188 keys[i]) +
189 1;
190 n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
191 values[i]) +
192 1;
193 }
194
195 m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n -
196 sizeof(struct udphdr);
197 tftp_udp_output(spt, m, recv_tp);
198
199 return 0;
200 }
201
202 static void tftp_send_error(struct tftp_session *spt, uint16_t errorcode,
203 const char *msg, struct tftp_t *recv_tp)
204 {
205 struct mbuf *m;
206 struct tftp_t *tp;
207
208 DEBUG_TFTP("tftp error msg: %s", msg);
209
210 m = m_get(spt->slirp);
211
212 if (!m) {
213 goto out;
214 }
215
216 tp = tftp_prep_mbuf_data(spt, m);
217
218 tp->tp_op = htons(TFTP_ERROR);
219 tp->x.tp_error.tp_error_code = htons(errorcode);
220 slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg),
221 msg);
222
223 m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 +
224 strlen(msg) - sizeof(struct udphdr);
225 tftp_udp_output(spt, m, recv_tp);
226
227 out:
228 tftp_session_terminate(spt);
229 }
230
231 static void tftp_send_next_block(struct tftp_session *spt,
232 struct tftp_t *recv_tp)
233 {
234 struct mbuf *m;
235 struct tftp_t *tp;
236 int nobytes;
237
238 m = m_get(spt->slirp);
239
240 if (!m) {
241 return;
242 }
243
244 tp = tftp_prep_mbuf_data(spt, m);
245
246 tp->tp_op = htons(TFTP_DATA);
247 tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
248
249 nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
250 spt->block_size);
251
252 if (nobytes < 0) {
253 m_free(m);
254
255 /* send "file not found" error back */
256
257 tftp_send_error(spt, 1, "File not found", tp);
258
259 return;
260 }
261
262 m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) -
263 sizeof(struct udphdr);
264 tftp_udp_output(spt, m, recv_tp);
265
266 if (nobytes == spt->block_size) {
267 tftp_session_update(spt);
268 } else {
269 tftp_session_terminate(spt);
270 }
271
272 spt->block_nr++;
273 }
274
275 static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
276 struct tftp_t *tp, int pktlen)
277 {
278 struct tftp_session *spt;
279 int s, k;
280 size_t prefix_len;
281 char *req_fname;
282 const char *option_name[2];
283 uint32_t option_value[2];
284 int nb_options = 0;
285
286 /* check if a session already exists and if so terminate it */
287 s = tftp_session_find(slirp, srcsas, tp);
288 if (s >= 0) {
289 tftp_session_terminate(&slirp->tftp_sessions[s]);
290 }
291
292 s = tftp_session_allocate(slirp, srcsas, tp);
293
294 if (s < 0) {
295 return;
296 }
297
298 spt = &slirp->tftp_sessions[s];
299
300 /* unspecified prefix means service disabled */
301 if (!slirp->tftp_prefix) {
302 tftp_send_error(spt, 2, "Access violation", tp);
303 return;
304 }
305
306 /* skip header fields */
307 k = 0;
308 pktlen -= offsetof(struct tftp_t, x.tp_buf);
309
310 /* prepend tftp_prefix */
311 prefix_len = strlen(slirp->tftp_prefix);
312 spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
313 memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
314 spt->filename[prefix_len] = '/';
315
316 /* get name */
317 req_fname = spt->filename + prefix_len + 1;
318
319 while (1) {
320 if (k >= TFTP_FILENAME_MAX || k >= pktlen) {
321 tftp_send_error(spt, 2, "Access violation", tp);
322 return;
323 }
324 req_fname[k] = tp->x.tp_buf[k];
325 if (req_fname[k++] == '\0') {
326 break;
327 }
328 }
329
330 DEBUG_TFTP("tftp rrq file: %s", req_fname);
331
332 /* check mode */
333 if ((pktlen - k) < 6) {
334 tftp_send_error(spt, 2, "Access violation", tp);
335 return;
336 }
337
338 if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
339 tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
340 return;
341 }
342
343 k += 6; /* skipping octet */
344
345 /* do sanity checks on the filename */
346 if (!strncmp(req_fname, "../", 3) ||
347 req_fname[strlen(req_fname) - 1] == '/' || strstr(req_fname, "/../")) {
348 tftp_send_error(spt, 2, "Access violation", tp);
349 return;
350 }
351
352 /* check if the file exists */
353 if (tftp_read_data(spt, 0, NULL, 0) < 0) {
354 tftp_send_error(spt, 1, "File not found", tp);
355 return;
356 }
357
358 if (tp->x.tp_buf[pktlen - 1] != 0) {
359 tftp_send_error(spt, 2, "Access violation", tp);
360 return;
361 }
362
363 while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) {
364 const char *key, *value;
365
366 key = &tp->x.tp_buf[k];
367 k += strlen(key) + 1;
368
369 if (k >= pktlen) {
370 tftp_send_error(spt, 2, "Access violation", tp);
371 return;
372 }
373
374 value = &tp->x.tp_buf[k];
375 k += strlen(value) + 1;
376
377 if (strcasecmp(key, "tsize") == 0) {
378 int tsize = atoi(value);
379 struct stat stat_p;
380
381 if (tsize == 0) {
382 if (stat(spt->filename, &stat_p) == 0)
383 tsize = stat_p.st_size;
384 else {
385 tftp_send_error(spt, 1, "File not found", tp);
386 return;
387 }
388 }
389
390 option_name[nb_options] = "tsize";
391 option_value[nb_options] = tsize;
392 nb_options++;
393 } else if (strcasecmp(key, "blksize") == 0) {
394 int blksize = atoi(value);
395
396 /* Accept blksize up to our maximum size */
397 if (blksize > 0) {
398 spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX);
399 option_name[nb_options] = "blksize";
400 option_value[nb_options] = spt->block_size;
401 nb_options++;
402 }
403 }
404 }
405
406 if (nb_options > 0) {
407 assert(nb_options <= G_N_ELEMENTS(option_name));
408 tftp_send_oack(spt, option_name, option_value, nb_options, tp);
409 return;
410 }
411
412 spt->block_nr = 0;
413 tftp_send_next_block(spt, tp);
414 }
415
416 static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
417 struct tftp_t *tp, int pktlen)
418 {
419 int s;
420
421 s = tftp_session_find(slirp, srcsas, tp);
422
423 if (s < 0) {
424 return;
425 }
426
427 tftp_send_next_block(&slirp->tftp_sessions[s], tp);
428 }
429
430 static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
431 struct tftp_t *tp, int pktlen)
432 {
433 int s;
434
435 s = tftp_session_find(slirp, srcsas, tp);
436
437 if (s < 0) {
438 return;
439 }
440
441 tftp_session_terminate(&slirp->tftp_sessions[s]);
442 }
443
444 void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
445 {
446 struct tftp_t *tp = (struct tftp_t *)m->m_data;
447
448 switch (ntohs(tp->tp_op)) {
449 case TFTP_RRQ:
450 tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
451 break;
452
453 case TFTP_ACK:
454 tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
455 break;
456
457 case TFTP_ERROR:
458 tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
459 break;
460 }
461 }
+0
-52
vendor/libslirp/src/tftp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /* tftp defines */
2
3 #ifndef SLIRP_TFTP_H
4 #define SLIRP_TFTP_H
5
6 #define TFTP_SESSIONS_MAX 20
7
8 #define TFTP_SERVER 69
9
10 #define TFTP_RRQ 1
11 #define TFTP_WRQ 2
12 #define TFTP_DATA 3
13 #define TFTP_ACK 4
14 #define TFTP_ERROR 5
15 #define TFTP_OACK 6
16
17 #define TFTP_FILENAME_MAX 512
18 #define TFTP_BLOCKSIZE_MAX 1428
19
20 struct tftp_t {
21 struct udphdr udp;
22 uint16_t tp_op;
23 union {
24 struct {
25 uint16_t tp_block_nr;
26 uint8_t tp_buf[TFTP_BLOCKSIZE_MAX];
27 } tp_data;
28 struct {
29 uint16_t tp_error_code;
30 uint8_t tp_msg[TFTP_BLOCKSIZE_MAX];
31 } tp_error;
32 char tp_buf[TFTP_BLOCKSIZE_MAX + 2];
33 } x;
34 } __attribute__((packed));
35
36 struct tftp_session {
37 Slirp *slirp;
38 char *filename;
39 int fd;
40 uint16_t block_size;
41
42 struct sockaddr_storage client_addr;
43 uint16_t client_port;
44 uint32_t block_nr;
45
46 int timestamp;
47 };
48
49 void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
50
51 #endif
+0
-355
vendor/libslirp/src/udp.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
30 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP
35 * Copyright (c) 1995 Danny Gasparovski.
36 *
37 * Please read the file COPYRIGHT for the
38 * terms and conditions of the copyright.
39 */
40
41 #include "slirp.h"
42 #include "ip_icmp.h"
43
44 static uint8_t udp_tos(struct socket *so);
45
46 void udp_init(Slirp *slirp)
47 {
48 slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
49 slirp->udp_last_so = &slirp->udb;
50 }
51
52 void udp_cleanup(Slirp *slirp)
53 {
54 while (slirp->udb.so_next != &slirp->udb) {
55 udp_detach(slirp->udb.so_next);
56 }
57 }
58
59 /* m->m_data points at ip packet header
60 * m->m_len length ip packet
61 * ip->ip_len length data (IPDU)
62 */
63 void udp_input(register struct mbuf *m, int iphlen)
64 {
65 Slirp *slirp = m->slirp;
66 register struct ip *ip;
67 register struct udphdr *uh;
68 int len;
69 struct ip save_ip;
70 struct socket *so;
71 struct sockaddr_storage lhost;
72 struct sockaddr_in *lhost4;
73
74 DEBUG_CALL("udp_input");
75 DEBUG_ARG("m = %p", m);
76 DEBUG_ARG("iphlen = %d", iphlen);
77
78 /*
79 * Strip IP options, if any; should skip this,
80 * make available to user, and use on returned packets,
81 * but we don't yet have a way to check the checksum
82 * with options still present.
83 */
84 if (iphlen > sizeof(struct ip)) {
85 ip_stripoptions(m, (struct mbuf *)0);
86 iphlen = sizeof(struct ip);
87 }
88
89 /*
90 * Get IP and UDP header together in first mbuf.
91 */
92 ip = mtod(m, struct ip *);
93 uh = (struct udphdr *)((char *)ip + iphlen);
94
95 /*
96 * Make mbuf data length reflect UDP length.
97 * If not enough data to reflect UDP length, drop.
98 */
99 len = ntohs((uint16_t)uh->uh_ulen);
100
101 if (ip->ip_len != len) {
102 if (len > ip->ip_len) {
103 goto bad;
104 }
105 m_adj(m, len - ip->ip_len);
106 ip->ip_len = len;
107 }
108
109 /*
110 * Save a copy of the IP header in case we want restore it
111 * for sending an ICMP error message in response.
112 */
113 save_ip = *ip;
114 save_ip.ip_len += iphlen; /* tcp_input subtracts this */
115
116 /*
117 * Checksum extended UDP header and data.
118 */
119 if (uh->uh_sum) {
120 memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
121 ((struct ipovly *)ip)->ih_x1 = 0;
122 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
123 if (cksum(m, len + sizeof(struct ip))) {
124 goto bad;
125 }
126 }
127
128 lhost.ss_family = AF_INET;
129 lhost4 = (struct sockaddr_in *)&lhost;
130 lhost4->sin_addr = ip->ip_src;
131 lhost4->sin_port = uh->uh_sport;
132
133 /*
134 * handle DHCP/BOOTP
135 */
136 if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
137 (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
138 ip->ip_dst.s_addr == 0xffffffff)) {
139 bootp_input(m);
140 goto bad;
141 }
142
143 /*
144 * handle TFTP
145 */
146 if (ntohs(uh->uh_dport) == TFTP_SERVER &&
147 ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
148 m->m_data += iphlen;
149 m->m_len -= iphlen;
150 tftp_input(&lhost, m);
151 m->m_data -= iphlen;
152 m->m_len += iphlen;
153 goto bad;
154 }
155
156 if (slirp->restricted) {
157 goto bad;
158 }
159
160 /*
161 * Locate pcb for datagram.
162 */
163 so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
164
165 if (so == NULL) {
166 /*
167 * If there's no socket for this packet,
168 * create one
169 */
170 so = socreate(slirp);
171 if (udp_attach(so, AF_INET) == -1) {
172 DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));
173 sofree(so);
174 goto bad;
175 }
176
177 /*
178 * Setup fields
179 */
180 so->so_lfamily = AF_INET;
181 so->so_laddr = ip->ip_src;
182 so->so_lport = uh->uh_sport;
183
184 if ((so->so_iptos = udp_tos(so)) == 0)
185 so->so_iptos = ip->ip_tos;
186
187 /*
188 * XXXXX Here, check if it's in udpexec_list,
189 * and if it is, do the fork_exec() etc.
190 */
191 }
192
193 so->so_ffamily = AF_INET;
194 so->so_faddr = ip->ip_dst; /* XXX */
195 so->so_fport = uh->uh_dport; /* XXX */
196
197 iphlen += sizeof(struct udphdr);
198 m->m_len -= iphlen;
199 m->m_data += iphlen;
200
201 /*
202 * Now we sendto() the packet.
203 */
204 if (sosendto(so, m) == -1) {
205 m->m_len += iphlen;
206 m->m_data -= iphlen;
207 *ip = save_ip;
208 DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
209 icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
210 goto bad;
211 }
212
213 m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
214
215 /* restore the orig mbuf packet */
216 m->m_len += iphlen;
217 m->m_data -= iphlen;
218 *ip = save_ip;
219 so->so_m = m; /* ICMP backup */
220
221 return;
222 bad:
223 m_free(m);
224 }
225
226 int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
227 struct sockaddr_in *daddr, int iptos)
228 {
229 register struct udpiphdr *ui;
230 int error = 0;
231
232 DEBUG_CALL("udp_output");
233 DEBUG_ARG("so = %p", so);
234 DEBUG_ARG("m = %p", m);
235 DEBUG_ARG("saddr = %s", inet_ntoa(saddr->sin_addr));
236 DEBUG_ARG("daddr = %s", inet_ntoa(daddr->sin_addr));
237
238 /*
239 * Adjust for header
240 */
241 m->m_data -= sizeof(struct udpiphdr);
242 m->m_len += sizeof(struct udpiphdr);
243
244 /*
245 * Fill in mbuf with extended UDP header
246 * and addresses and length put into network format.
247 */
248 ui = mtod(m, struct udpiphdr *);
249 memset(&ui->ui_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));
250 ui->ui_x1 = 0;
251 ui->ui_pr = IPPROTO_UDP;
252 ui->ui_len = htons(m->m_len - sizeof(struct ip));
253 /* XXXXX Check for from-one-location sockets, or from-any-location sockets
254 */
255 ui->ui_src = saddr->sin_addr;
256 ui->ui_dst = daddr->sin_addr;
257 ui->ui_sport = saddr->sin_port;
258 ui->ui_dport = daddr->sin_port;
259 ui->ui_ulen = ui->ui_len;
260
261 /*
262 * Stuff checksum and output datagram.
263 */
264 ui->ui_sum = 0;
265 if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
266 ui->ui_sum = 0xffff;
267 ((struct ip *)ui)->ip_len = m->m_len;
268
269 ((struct ip *)ui)->ip_ttl = IPDEFTTL;
270 ((struct ip *)ui)->ip_tos = iptos;
271
272 error = ip_output(so, m);
273
274 return (error);
275 }
276
277 int udp_attach(struct socket *so, unsigned short af)
278 {
279 so->s = slirp_socket(af, SOCK_DGRAM, 0);
280 if (so->s != -1) {
281 so->so_expire = curtime + SO_EXPIRE;
282 insque(so, &so->slirp->udb);
283 }
284 return (so->s);
285 }
286
287 void udp_detach(struct socket *so)
288 {
289 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
290 closesocket(so->s);
291 sofree(so);
292 }
293
294 static const struct tos_t udptos[] = { { 0, 53, IPTOS_LOWDELAY, 0 }, /* DNS */
295 { 0, 0, 0, 0 } };
296
297 static uint8_t udp_tos(struct socket *so)
298 {
299 int i = 0;
300
301 while (udptos[i].tos) {
302 if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
303 (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
304 if (so->slirp->enable_emu)
305 so->so_emu = udptos[i].emu;
306 return udptos[i].tos;
307 }
308 i++;
309 }
310
311 return 0;
312 }
313
314 struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
315 uint32_t laddr, unsigned lport, int flags)
316 {
317 /* TODO: IPv6 */
318 struct sockaddr_in addr;
319 struct socket *so;
320 socklen_t addrlen = sizeof(struct sockaddr_in);
321
322 so = socreate(slirp);
323 so->s = slirp_socket(AF_INET, SOCK_DGRAM, 0);
324 if (so->s < 0) {
325 sofree(so);
326 return NULL;
327 }
328 so->so_expire = curtime + SO_EXPIRE;
329 insque(so, &slirp->udb);
330
331 addr.sin_family = AF_INET;
332 addr.sin_addr.s_addr = haddr;
333 addr.sin_port = hport;
334
335 if (bind(so->s, (struct sockaddr *)&addr, addrlen) < 0) {
336 udp_detach(so);
337 return NULL;
338 }
339 slirp_socket_set_fast_reuse(so->s);
340
341 getsockname(so->s, (struct sockaddr *)&addr, &addrlen);
342 so->fhost.sin = addr;
343 sotranslate_accept(so);
344 so->so_lfamily = AF_INET;
345 so->so_lport = lport;
346 so->so_laddr.s_addr = laddr;
347 if (flags != SS_FACCEPTONCE)
348 so->so_expire = 0;
349
350 so->so_state &= SS_PERSISTENT_MASK;
351 so->so_state |= SS_ISFCONNECTED | flags;
352
353 return so;
354 }
+0
-90
vendor/libslirp/src/udp.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 1982, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)udp.h 8.1 (Berkeley) 6/10/93
30 * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp
31 */
32
33 #ifndef UDP_H
34 #define UDP_H
35
36 #define UDP_TTL 0x60
37 #define UDP_UDPDATALEN 16192
38
39 /*
40 * Udp protocol header.
41 * Per RFC 768, September, 1981.
42 */
43 struct udphdr {
44 uint16_t uh_sport; /* source port */
45 uint16_t uh_dport; /* destination port */
46 int16_t uh_ulen; /* udp length */
47 uint16_t uh_sum; /* udp checksum */
48 };
49
50 /*
51 * UDP kernel structures and variables.
52 */
53 struct udpiphdr {
54 struct ipovly ui_i; /* overlaid ip structure */
55 struct udphdr ui_u; /* udp header */
56 };
57 #define ui_mbuf ui_i.ih_mbuf.mptr
58 #define ui_x1 ui_i.ih_x1
59 #define ui_pr ui_i.ih_pr
60 #define ui_len ui_i.ih_len
61 #define ui_src ui_i.ih_src
62 #define ui_dst ui_i.ih_dst
63 #define ui_sport ui_u.uh_sport
64 #define ui_dport ui_u.uh_dport
65 #define ui_ulen ui_u.uh_ulen
66 #define ui_sum ui_u.uh_sum
67
68 /*
69 * Names for UDP sysctl objects
70 */
71 #define UDPCTL_CHECKSUM 1 /* checksum UDP packets */
72 #define UDPCTL_MAXID 2
73
74 struct mbuf;
75
76 void udp_init(Slirp *);
77 void udp_cleanup(Slirp *);
78 void udp_input(register struct mbuf *, int);
79 int udp_attach(struct socket *, unsigned short af);
80 void udp_detach(struct socket *);
81 struct socket *udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
82 int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
83 struct sockaddr_in *daddr, int iptos);
84
85 void udp6_input(register struct mbuf *);
86 int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr,
87 struct sockaddr_in6 *daddr);
88
89 #endif
+0
-173
vendor/libslirp/src/udp6.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron
4 */
5
6 #include "slirp.h"
7 #include "udp.h"
8 #include "dhcpv6.h"
9
10 void udp6_input(struct mbuf *m)
11 {
12 Slirp *slirp = m->slirp;
13 struct ip6 *ip, save_ip;
14 struct udphdr *uh;
15 int iphlen = sizeof(struct ip6);
16 int len;
17 struct socket *so;
18 struct sockaddr_in6 lhost;
19
20 DEBUG_CALL("udp6_input");
21 DEBUG_ARG("m = %p", m);
22
23 if (slirp->restricted) {
24 goto bad;
25 }
26
27 ip = mtod(m, struct ip6 *);
28 m->m_len -= iphlen;
29 m->m_data += iphlen;
30 uh = mtod(m, struct udphdr *);
31 m->m_len += iphlen;
32 m->m_data -= iphlen;
33
34 if (ip6_cksum(m)) {
35 goto bad;
36 }
37
38 len = ntohs((uint16_t)uh->uh_ulen);
39
40 /*
41 * Make mbuf data length reflect UDP length.
42 * If not enough data to reflect UDP length, drop.
43 */
44 if (ntohs(ip->ip_pl) != len) {
45 if (len > ntohs(ip->ip_pl)) {
46 goto bad;
47 }
48 m_adj(m, len - ntohs(ip->ip_pl));
49 ip->ip_pl = htons(len);
50 }
51
52 /*
53 * Save a copy of the IP header in case we want restore it
54 * for sending an ICMP error message in response.
55 */
56 save_ip = *ip;
57
58 /* Locate pcb for datagram. */
59 lhost.sin6_family = AF_INET6;
60 lhost.sin6_addr = ip->ip_src;
61 lhost.sin6_port = uh->uh_sport;
62
63 /* handle DHCPv6 */
64 if (ntohs(uh->uh_dport) == DHCPV6_SERVER_PORT &&
65 (in6_equal(&ip->ip_dst, &slirp->vhost_addr6) ||
66 in6_dhcp_multicast(&ip->ip_dst))) {
67 m->m_data += iphlen;
68 m->m_len -= iphlen;
69 dhcpv6_input(&lhost, m);
70 m->m_data -= iphlen;
71 m->m_len += iphlen;
72 goto bad;
73 }
74
75 /* handle TFTP */
76 if (ntohs(uh->uh_dport) == TFTP_SERVER &&
77 !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
78 m->m_data += iphlen;
79 m->m_len -= iphlen;
80 tftp_input((struct sockaddr_storage *)&lhost, m);
81 m->m_data -= iphlen;
82 m->m_len += iphlen;
83 goto bad;
84 }
85
86 so = solookup(&slirp->udp_last_so, &slirp->udb,
87 (struct sockaddr_storage *)&lhost, NULL);
88
89 if (so == NULL) {
90 /* If there's no socket for this packet, create one. */
91 so = socreate(slirp);
92 if (udp_attach(so, AF_INET6) == -1) {
93 DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno));
94 sofree(so);
95 goto bad;
96 }
97
98 /* Setup fields */
99 so->so_lfamily = AF_INET6;
100 so->so_laddr6 = ip->ip_src;
101 so->so_lport6 = uh->uh_sport;
102 }
103
104 so->so_ffamily = AF_INET6;
105 so->so_faddr6 = ip->ip_dst; /* XXX */
106 so->so_fport6 = uh->uh_dport; /* XXX */
107
108 iphlen += sizeof(struct udphdr);
109 m->m_len -= iphlen;
110 m->m_data += iphlen;
111
112 /*
113 * Now we sendto() the packet.
114 */
115 if (sosendto(so, m) == -1) {
116 m->m_len += iphlen;
117 m->m_data -= iphlen;
118 *ip = save_ip;
119 DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
120 icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
121 goto bad;
122 }
123
124 m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
125
126 /* restore the orig mbuf packet */
127 m->m_len += iphlen;
128 m->m_data -= iphlen;
129 *ip = save_ip;
130 so->so_m = m;
131
132 return;
133 bad:
134 m_free(m);
135 }
136
137 int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr,
138 struct sockaddr_in6 *daddr)
139 {
140 struct ip6 *ip;
141 struct udphdr *uh;
142
143 DEBUG_CALL("udp6_output");
144 DEBUG_ARG("so = %p", so);
145 DEBUG_ARG("m = %p", m);
146
147 /* adjust for header */
148 m->m_data -= sizeof(struct udphdr);
149 m->m_len += sizeof(struct udphdr);
150 uh = mtod(m, struct udphdr *);
151 m->m_data -= sizeof(struct ip6);
152 m->m_len += sizeof(struct ip6);
153 ip = mtod(m, struct ip6 *);
154
155 /* Build IP header */
156 ip->ip_pl = htons(m->m_len - sizeof(struct ip6));
157 ip->ip_nh = IPPROTO_UDP;
158 ip->ip_src = saddr->sin6_addr;
159 ip->ip_dst = daddr->sin6_addr;
160
161 /* Build UDP header */
162 uh->uh_sport = saddr->sin6_port;
163 uh->uh_dport = daddr->sin6_port;
164 uh->uh_ulen = ip->ip_pl;
165 uh->uh_sum = 0;
166 uh->uh_sum = ip6_cksum(m);
167 if (uh->uh_sum == 0) {
168 uh->uh_sum = 0xffff;
169 }
170
171 return ip6_output(so, m, 0);
172 }
+0
-366
vendor/libslirp/src/util.c less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * util.c (mostly based on QEMU os-win32.c)
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 * Copyright (c) 2010-2016 Red Hat, Inc.
6 *
7 * QEMU library functions for win32 which are shared between QEMU and
8 * the QEMU tools.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 */
28 #include "util.h"
29
30 #include <glib.h>
31 #include <fcntl.h>
32 #include <stdint.h>
33
34 #if defined(_WIN32)
35 int slirp_inet_aton(const char *cp, struct in_addr *ia)
36 {
37 uint32_t addr = inet_addr(cp);
38 if (addr == 0xffffffff) {
39 return 0;
40 }
41 ia->s_addr = addr;
42 return 1;
43 }
44 #endif
45
46 void slirp_set_nonblock(int fd)
47 {
48 #ifndef _WIN32
49 int f;
50 f = fcntl(fd, F_GETFL);
51 assert(f != -1);
52 f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
53 assert(f != -1);
54 #else
55 unsigned long opt = 1;
56 ioctlsocket(fd, FIONBIO, &opt);
57 #endif
58 }
59
60 static void slirp_set_cloexec(int fd)
61 {
62 #ifndef _WIN32
63 int f;
64 f = fcntl(fd, F_GETFD);
65 assert(f != -1);
66 f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
67 assert(f != -1);
68 #endif
69 }
70
71 /*
72 * Opens a socket with FD_CLOEXEC set
73 */
74 int slirp_socket(int domain, int type, int protocol)
75 {
76 int ret;
77
78 #ifdef SOCK_CLOEXEC
79 ret = socket(domain, type | SOCK_CLOEXEC, protocol);
80 if (ret != -1 || errno != EINVAL) {
81 return ret;
82 }
83 #endif
84 ret = socket(domain, type, protocol);
85 if (ret >= 0) {
86 slirp_set_cloexec(ret);
87 }
88
89 return ret;
90 }
91
92 #ifdef _WIN32
93 static int socket_error(void)
94 {
95 switch (WSAGetLastError()) {
96 case 0:
97 return 0;
98 case WSAEINTR:
99 return EINTR;
100 case WSAEINVAL:
101 return EINVAL;
102 case WSA_INVALID_HANDLE:
103 return EBADF;
104 case WSA_NOT_ENOUGH_MEMORY:
105 return ENOMEM;
106 case WSA_INVALID_PARAMETER:
107 return EINVAL;
108 case WSAENAMETOOLONG:
109 return ENAMETOOLONG;
110 case WSAENOTEMPTY:
111 return ENOTEMPTY;
112 case WSAEWOULDBLOCK:
113 /* not using EWOULDBLOCK as we don't want code to have
114 * to check both EWOULDBLOCK and EAGAIN */
115 return EAGAIN;
116 case WSAEINPROGRESS:
117 return EINPROGRESS;
118 case WSAEALREADY:
119 return EALREADY;
120 case WSAENOTSOCK:
121 return ENOTSOCK;
122 case WSAEDESTADDRREQ:
123 return EDESTADDRREQ;
124 case WSAEMSGSIZE:
125 return EMSGSIZE;
126 case WSAEPROTOTYPE:
127 return EPROTOTYPE;
128 case WSAENOPROTOOPT:
129 return ENOPROTOOPT;
130 case WSAEPROTONOSUPPORT:
131 return EPROTONOSUPPORT;
132 case WSAEOPNOTSUPP:
133 return EOPNOTSUPP;
134 case WSAEAFNOSUPPORT:
135 return EAFNOSUPPORT;
136 case WSAEADDRINUSE:
137 return EADDRINUSE;
138 case WSAEADDRNOTAVAIL:
139 return EADDRNOTAVAIL;
140 case WSAENETDOWN:
141 return ENETDOWN;
142 case WSAENETUNREACH:
143 return ENETUNREACH;
144 case WSAENETRESET:
145 return ENETRESET;
146 case WSAECONNABORTED:
147 return ECONNABORTED;
148 case WSAECONNRESET:
149 return ECONNRESET;
150 case WSAENOBUFS:
151 return ENOBUFS;
152 case WSAEISCONN:
153 return EISCONN;
154 case WSAENOTCONN:
155 return ENOTCONN;
156 case WSAETIMEDOUT:
157 return ETIMEDOUT;
158 case WSAECONNREFUSED:
159 return ECONNREFUSED;
160 case WSAELOOP:
161 return ELOOP;
162 case WSAEHOSTUNREACH:
163 return EHOSTUNREACH;
164 default:
165 return EIO;
166 }
167 }
168
169 #undef ioctlsocket
170 int slirp_ioctlsocket_wrap(int fd, int req, void *val)
171 {
172 int ret;
173 ret = ioctlsocket(fd, req, val);
174 if (ret < 0) {
175 errno = socket_error();
176 }
177 return ret;
178 }
179
180 #undef closesocket
181 int slirp_closesocket_wrap(int fd)
182 {
183 int ret;
184 ret = closesocket(fd);
185 if (ret < 0) {
186 errno = socket_error();
187 }
188 return ret;
189 }
190
191 #undef connect
192 int slirp_connect_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
193 {
194 int ret;
195 ret = connect(sockfd, addr, addrlen);
196 if (ret < 0) {
197 errno = socket_error();
198 }
199 return ret;
200 }
201
202 #undef listen
203 int slirp_listen_wrap(int sockfd, int backlog)
204 {
205 int ret;
206 ret = listen(sockfd, backlog);
207 if (ret < 0) {
208 errno = socket_error();
209 }
210 return ret;
211 }
212
213 #undef bind
214 int slirp_bind_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
215 {
216 int ret;
217 ret = bind(sockfd, addr, addrlen);
218 if (ret < 0) {
219 errno = socket_error();
220 }
221 return ret;
222 }
223
224 #undef socket
225 int slirp_socket_wrap(int domain, int type, int protocol)
226 {
227 int ret;
228 ret = socket(domain, type, protocol);
229 if (ret < 0) {
230 errno = socket_error();
231 }
232 return ret;
233 }
234
235 #undef accept
236 int slirp_accept_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
237 {
238 int ret;
239 ret = accept(sockfd, addr, addrlen);
240 if (ret < 0) {
241 errno = socket_error();
242 }
243 return ret;
244 }
245
246 #undef shutdown
247 int slirp_shutdown_wrap(int sockfd, int how)
248 {
249 int ret;
250 ret = shutdown(sockfd, how);
251 if (ret < 0) {
252 errno = socket_error();
253 }
254 return ret;
255 }
256
257 #undef getsockopt
258 int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval,
259 int *optlen)
260 {
261 int ret;
262 ret = getsockopt(sockfd, level, optname, optval, optlen);
263 if (ret < 0) {
264 errno = socket_error();
265 }
266 return ret;
267 }
268
269 #undef setsockopt
270 int slirp_setsockopt_wrap(int sockfd, int level, int optname,
271 const void *optval, int optlen)
272 {
273 int ret;
274 ret = setsockopt(sockfd, level, optname, optval, optlen);
275 if (ret < 0) {
276 errno = socket_error();
277 }
278 return ret;
279 }
280
281 #undef getpeername
282 int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
283 {
284 int ret;
285 ret = getpeername(sockfd, addr, addrlen);
286 if (ret < 0) {
287 errno = socket_error();
288 }
289 return ret;
290 }
291
292 #undef getsockname
293 int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
294 {
295 int ret;
296 ret = getsockname(sockfd, addr, addrlen);
297 if (ret < 0) {
298 errno = socket_error();
299 }
300 return ret;
301 }
302
303 #undef send
304 ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags)
305 {
306 int ret;
307 ret = send(sockfd, buf, len, flags);
308 if (ret < 0) {
309 errno = socket_error();
310 }
311 return ret;
312 }
313
314 #undef sendto
315 ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
316 const struct sockaddr *addr, int addrlen)
317 {
318 int ret;
319 ret = sendto(sockfd, buf, len, flags, addr, addrlen);
320 if (ret < 0) {
321 errno = socket_error();
322 }
323 return ret;
324 }
325
326 #undef recv
327 ssize_t slirp_recv_wrap(int sockfd, void *buf, size_t len, int flags)
328 {
329 int ret;
330 ret = recv(sockfd, buf, len, flags);
331 if (ret < 0) {
332 errno = socket_error();
333 }
334 return ret;
335 }
336
337 #undef recvfrom
338 ssize_t slirp_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
339 struct sockaddr *addr, int *addrlen)
340 {
341 int ret;
342 ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
343 if (ret < 0) {
344 errno = socket_error();
345 }
346 return ret;
347 }
348 #endif /* WIN32 */
349
350 void slirp_pstrcpy(char *buf, int buf_size, const char *str)
351 {
352 int c;
353 char *q = buf;
354
355 if (buf_size <= 0)
356 return;
357
358 for (;;) {
359 c = *str++;
360 if (c == 0 || q >= buf + buf_size - 1)
361 break;
362 *q++ = c;
363 }
364 *q = '\0';
365 }
+0
-180
vendor/libslirp/src/util.h less more
0 /* SPDX-License-Identifier: MIT */
1 /*
2 * Copyright (c) 2003-2008 Fabrice Bellard
3 * Copyright (c) 2010-2019 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23 #ifndef UTIL_H_
24 #define UTIL_H_
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <inttypes.h>
35
36 #ifdef _WIN32
37 #include <winsock2.h>
38 #include <windows.h>
39 #else
40 #include <sys/socket.h>
41 #include <netinet/tcp.h>
42 #include <netinet/in.h>
43 #endif
44
45 #if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
46 #define SLIRP_PACKED __attribute__((gcc_struct, packed))
47 #else
48 #define SLIRP_PACKED __attribute__((packed))
49 #endif
50
51 #ifndef DIV_ROUND_UP
52 #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
53 #endif
54
55 #ifndef container_of
56 #define container_of(ptr, type, member) \
57 __extension__({ \
58 void *__mptr = (void *)(ptr); \
59 ((type *)(__mptr - offsetof(type, member))); \
60 })
61 #endif
62
63 #if defined(_WIN32) /* CONFIG_IOVEC */
64 #if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */
65 struct iovec {
66 void *iov_base;
67 size_t iov_len;
68 };
69 #endif
70 #else
71 #include <sys/uio.h>
72 #endif
73
74 #define stringify(s) tostring(s)
75 #define tostring(s) #s
76
77 #define SCALE_MS 1000000
78
79 #define ETH_ALEN 6
80 #define ETH_HLEN 14
81 #define ETH_P_IP (0x0800) /* Internet Protocol packet */
82 #define ETH_P_ARP (0x0806) /* Address Resolution packet */
83 #define ETH_P_IPV6 (0x86dd)
84 #define ETH_P_VLAN (0x8100)
85 #define ETH_P_DVLAN (0x88a8)
86 #define ETH_P_NCSI (0x88f8)
87 #define ETH_P_UNKNOWN (0xffff)
88
89 /* FIXME: remove me when made standalone */
90 #ifdef _WIN32
91 #undef accept
92 #undef bind
93 #undef closesocket
94 #undef connect
95 #undef getpeername
96 #undef getsockname
97 #undef getsockopt
98 #undef ioctlsocket
99 #undef listen
100 #undef recv
101 #undef recvfrom
102 #undef send
103 #undef sendto
104 #undef setsockopt
105 #undef shutdown
106 #undef socket
107 #endif
108
109 #ifdef _WIN32
110 #define connect slirp_connect_wrap
111 int slirp_connect_wrap(int fd, const struct sockaddr *addr, int addrlen);
112 #define listen slirp_listen_wrap
113 int slirp_listen_wrap(int fd, int backlog);
114 #define bind slirp_bind_wrap
115 int slirp_bind_wrap(int fd, const struct sockaddr *addr, int addrlen);
116 #define socket slirp_socket_wrap
117 int slirp_socket_wrap(int domain, int type, int protocol);
118 #define accept slirp_accept_wrap
119 int slirp_accept_wrap(int fd, struct sockaddr *addr, int *addrlen);
120 #define shutdown slirp_shutdown_wrap
121 int slirp_shutdown_wrap(int fd, int how);
122 #define getpeername slirp_getpeername_wrap
123 int slirp_getpeername_wrap(int fd, struct sockaddr *addr, int *addrlen);
124 #define getsockname slirp_getsockname_wrap
125 int slirp_getsockname_wrap(int fd, struct sockaddr *addr, int *addrlen);
126 #define send slirp_send_wrap
127 ssize_t slirp_send_wrap(int fd, const void *buf, size_t len, int flags);
128 #define sendto slirp_sendto_wrap
129 ssize_t slirp_sendto_wrap(int fd, const void *buf, size_t len, int flags,
130 const struct sockaddr *dest_addr, int addrlen);
131 #define recv slirp_recv_wrap
132 ssize_t slirp_recv_wrap(int fd, void *buf, size_t len, int flags);
133 #define recvfrom slirp_recvfrom_wrap
134 ssize_t slirp_recvfrom_wrap(int fd, void *buf, size_t len, int flags,
135 struct sockaddr *src_addr, int *addrlen);
136 #define closesocket slirp_closesocket_wrap
137 int slirp_closesocket_wrap(int fd);
138 #define ioctlsocket slirp_ioctlsocket_wrap
139 int slirp_ioctlsocket_wrap(int fd, int req, void *val);
140 #define getsockopt slirp_getsockopt_wrap
141 int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval,
142 int *optlen);
143 #define setsockopt slirp_setsockopt_wrap
144 int slirp_setsockopt_wrap(int sockfd, int level, int optname,
145 const void *optval, int optlen);
146 #define inet_aton slirp_inet_aton
147 int slirp_inet_aton(const char *cp, struct in_addr *ia);
148 #else
149 #define closesocket(s) close(s)
150 #define ioctlsocket(s, r, v) ioctl(s, r, v)
151 #endif
152
153 int slirp_socket(int domain, int type, int protocol);
154 void slirp_set_nonblock(int fd);
155
156 static inline int slirp_socket_set_nodelay(int fd)
157 {
158 int v = 1;
159 return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
160 }
161
162 static inline int slirp_socket_set_fast_reuse(int fd)
163 {
164 #ifndef _WIN32
165 int v = 1;
166 return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
167 #else
168 /* Enabling the reuse of an endpoint that was used by a socket still in
169 * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
170 * fast reuse is the default and SO_REUSEADDR does strange things. So we
171 * don't have to do anything here. More info can be found at:
172 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
173 return 0;
174 #endif
175 }
176
177 void slirp_pstrcpy(char *buf, int buf_size, const char *str);
178
179 #endif
+0
-11
vendor/libslirp/src/version.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 #include "libslirp.h"
2 #include "util.h"
3
4 const char *
5 slirp_version_string(void)
6 {
7 return stringify(SLIRP_MAJOR_VERSION) "."
8 stringify(SLIRP_MINOR_VERSION) "."
9 stringify(SLIRP_MICRO_VERSION);
10 }
+0
-445
vendor/libslirp/src/vmstate.c less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * VMState interpreter
3 *
4 * Copyright (c) 2009-2018 Red Hat Inc
5 *
6 * Authors:
7 * Juan Quintela <quintela@redhat.com>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
21 *
22 * 3. Neither the name of the copyright holder nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37 * OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39 #include <assert.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <glib.h>
43
44 #include "stream.h"
45 #include "vmstate.h"
46
47 static int get_nullptr(SlirpIStream *f, void *pv, size_t size,
48 const VMStateField *field)
49 {
50 if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {
51 return 0;
52 }
53 g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
54 return -EINVAL;
55 }
56
57 static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
58 const VMStateField *field)
59
60 {
61 if (pv == NULL) {
62 slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);
63 return 0;
64 }
65 g_warning("vmstate: put_nullptr must be called with pv == NULL");
66 return -EINVAL;
67 }
68
69 const VMStateInfo slirp_vmstate_info_nullptr = {
70 .name = "uint64",
71 .get = get_nullptr,
72 .put = put_nullptr,
73 };
74
75 /* 8 bit unsigned int */
76
77 static int get_uint8(SlirpIStream *f, void *pv, size_t size,
78 const VMStateField *field)
79 {
80 uint8_t *v = pv;
81 *v = slirp_istream_read_u8(f);
82 return 0;
83 }
84
85 static int put_uint8(SlirpOStream *f, void *pv, size_t size,
86 const VMStateField *field)
87 {
88 uint8_t *v = pv;
89 slirp_ostream_write_u8(f, *v);
90 return 0;
91 }
92
93 const VMStateInfo slirp_vmstate_info_uint8 = {
94 .name = "uint8",
95 .get = get_uint8,
96 .put = put_uint8,
97 };
98
99 /* 16 bit unsigned int */
100
101 static int get_uint16(SlirpIStream *f, void *pv, size_t size,
102 const VMStateField *field)
103 {
104 uint16_t *v = pv;
105 *v = slirp_istream_read_u16(f);
106 return 0;
107 }
108
109 static int put_uint16(SlirpOStream *f, void *pv, size_t size,
110 const VMStateField *field)
111 {
112 uint16_t *v = pv;
113 slirp_ostream_write_u16(f, *v);
114 return 0;
115 }
116
117 const VMStateInfo slirp_vmstate_info_uint16 = {
118 .name = "uint16",
119 .get = get_uint16,
120 .put = put_uint16,
121 };
122
123 /* 32 bit unsigned int */
124
125 static int get_uint32(SlirpIStream *f, void *pv, size_t size,
126 const VMStateField *field)
127 {
128 uint32_t *v = pv;
129 *v = slirp_istream_read_u32(f);
130 return 0;
131 }
132
133 static int put_uint32(SlirpOStream *f, void *pv, size_t size,
134 const VMStateField *field)
135 {
136 uint32_t *v = pv;
137 slirp_ostream_write_u32(f, *v);
138 return 0;
139 }
140
141 const VMStateInfo slirp_vmstate_info_uint32 = {
142 .name = "uint32",
143 .get = get_uint32,
144 .put = put_uint32,
145 };
146
147 /* 16 bit int */
148
149 static int get_int16(SlirpIStream *f, void *pv, size_t size,
150 const VMStateField *field)
151 {
152 int16_t *v = pv;
153 *v = slirp_istream_read_i16(f);
154 return 0;
155 }
156
157 static int put_int16(SlirpOStream *f, void *pv, size_t size,
158 const VMStateField *field)
159 {
160 int16_t *v = pv;
161 slirp_ostream_write_i16(f, *v);
162 return 0;
163 }
164
165 const VMStateInfo slirp_vmstate_info_int16 = {
166 .name = "int16",
167 .get = get_int16,
168 .put = put_int16,
169 };
170
171 /* 32 bit int */
172
173 static int get_int32(SlirpIStream *f, void *pv, size_t size,
174 const VMStateField *field)
175 {
176 int32_t *v = pv;
177 *v = slirp_istream_read_i32(f);
178 return 0;
179 }
180
181 static int put_int32(SlirpOStream *f, void *pv, size_t size,
182 const VMStateField *field)
183 {
184 int32_t *v = pv;
185 slirp_ostream_write_i32(f, *v);
186 return 0;
187 }
188
189 const VMStateInfo slirp_vmstate_info_int32 = {
190 .name = "int32",
191 .get = get_int32,
192 .put = put_int32,
193 };
194
195 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
196 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
197 * copy stuff from the parent into the child and do calculations to fill
198 * in fields that don't really exist in the parent but need to be in the
199 * stream.
200 */
201 static int get_tmp(SlirpIStream *f, void *pv, size_t size,
202 const VMStateField *field)
203 {
204 int ret;
205 const VMStateDescription *vmsd = field->vmsd;
206 int version_id = field->version_id;
207 void *tmp = g_malloc(size);
208
209 /* Writes the parent field which is at the start of the tmp */
210 *(void **)tmp = pv;
211 ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
212 g_free(tmp);
213 return ret;
214 }
215
216 static int put_tmp(SlirpOStream *f, void *pv, size_t size,
217 const VMStateField *field)
218 {
219 const VMStateDescription *vmsd = field->vmsd;
220 void *tmp = g_malloc(size);
221 int ret;
222
223 /* Writes the parent field which is at the start of the tmp */
224 *(void **)tmp = pv;
225 ret = slirp_vmstate_save_state(f, vmsd, tmp);
226 g_free(tmp);
227
228 return ret;
229 }
230
231 const VMStateInfo slirp_vmstate_info_tmp = {
232 .name = "tmp",
233 .get = get_tmp,
234 .put = put_tmp,
235 };
236
237 /* uint8_t buffers */
238
239 static int get_buffer(SlirpIStream *f, void *pv, size_t size,
240 const VMStateField *field)
241 {
242 slirp_istream_read(f, pv, size);
243 return 0;
244 }
245
246 static int put_buffer(SlirpOStream *f, void *pv, size_t size,
247 const VMStateField *field)
248 {
249 slirp_ostream_write(f, pv, size);
250 return 0;
251 }
252
253 const VMStateInfo slirp_vmstate_info_buffer = {
254 .name = "buffer",
255 .get = get_buffer,
256 .put = put_buffer,
257 };
258
259 static int vmstate_n_elems(void *opaque, const VMStateField *field)
260 {
261 int n_elems = 1;
262
263 if (field->flags & VMS_ARRAY) {
264 n_elems = field->num;
265 } else if (field->flags & VMS_VARRAY_INT32) {
266 n_elems = *(int32_t *)(opaque + field->num_offset);
267 } else if (field->flags & VMS_VARRAY_UINT32) {
268 n_elems = *(uint32_t *)(opaque + field->num_offset);
269 } else if (field->flags & VMS_VARRAY_UINT16) {
270 n_elems = *(uint16_t *)(opaque + field->num_offset);
271 } else if (field->flags & VMS_VARRAY_UINT8) {
272 n_elems = *(uint8_t *)(opaque + field->num_offset);
273 }
274
275 if (field->flags & VMS_MULTIPLY_ELEMENTS) {
276 n_elems *= field->num;
277 }
278
279 return n_elems;
280 }
281
282 static int vmstate_size(void *opaque, const VMStateField *field)
283 {
284 int size = field->size;
285
286 if (field->flags & VMS_VBUFFER) {
287 size = *(int32_t *)(opaque + field->size_offset);
288 if (field->flags & VMS_MULTIPLY) {
289 size *= field->size;
290 }
291 }
292
293 return size;
294 }
295
296 static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
297 void *opaque, int version_id)
298 {
299 int ret = 0;
300 const VMStateField *field = vmsd->fields;
301
302 if (vmsd->pre_save) {
303 ret = vmsd->pre_save(opaque);
304 if (ret) {
305 g_warning("pre-save failed: %s", vmsd->name);
306 return ret;
307 }
308 }
309
310 while (field->name) {
311 if ((field->field_exists && field->field_exists(opaque, version_id)) ||
312 (!field->field_exists && field->version_id <= version_id)) {
313 void *first_elem = opaque + field->offset;
314 int i, n_elems = vmstate_n_elems(opaque, field);
315 int size = vmstate_size(opaque, field);
316
317 if (field->flags & VMS_POINTER) {
318 first_elem = *(void **)first_elem;
319 assert(first_elem || !n_elems || !size);
320 }
321 for (i = 0; i < n_elems; i++) {
322 void *curr_elem = first_elem + size * i;
323 ret = 0;
324
325 if (field->flags & VMS_ARRAY_OF_POINTER) {
326 assert(curr_elem);
327 curr_elem = *(void **)curr_elem;
328 }
329 if (!curr_elem && size) {
330 /* if null pointer write placeholder and do not follow */
331 assert(field->flags & VMS_ARRAY_OF_POINTER);
332 ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size,
333 NULL);
334 } else if (field->flags & VMS_STRUCT) {
335 ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);
336 } else if (field->flags & VMS_VSTRUCT) {
337 ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
338 field->struct_version_id);
339 } else {
340 ret = field->info->put(f, curr_elem, size, field);
341 }
342 if (ret) {
343 g_warning("Save of field %s/%s failed", vmsd->name,
344 field->name);
345 return ret;
346 }
347 }
348 } else {
349 if (field->flags & VMS_MUST_EXIST) {
350 g_warning("Output state validation failed: %s/%s", vmsd->name,
351 field->name);
352 assert(!(field->flags & VMS_MUST_EXIST));
353 }
354 }
355 field++;
356 }
357
358 return 0;
359 }
360
361 int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
362 void *opaque)
363 {
364 return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);
365 }
366
367 static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
368 {
369 if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
370 size_t size = vmstate_size(opaque, field);
371 size *= vmstate_n_elems(opaque, field);
372 if (size) {
373 *(void **)ptr = g_malloc(size);
374 }
375 }
376 }
377
378 int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
379 void *opaque, int version_id)
380 {
381 VMStateField *field = vmsd->fields;
382 int ret = 0;
383
384 if (version_id > vmsd->version_id) {
385 g_warning("%s: incoming version_id %d is too new "
386 "for local version_id %d",
387 vmsd->name, version_id, vmsd->version_id);
388 return -EINVAL;
389 }
390 if (vmsd->pre_load) {
391 int ret = vmsd->pre_load(opaque);
392 if (ret) {
393 return ret;
394 }
395 }
396 while (field->name) {
397 if ((field->field_exists && field->field_exists(opaque, version_id)) ||
398 (!field->field_exists && field->version_id <= version_id)) {
399 void *first_elem = opaque + field->offset;
400 int i, n_elems = vmstate_n_elems(opaque, field);
401 int size = vmstate_size(opaque, field);
402
403 vmstate_handle_alloc(first_elem, field, opaque);
404 if (field->flags & VMS_POINTER) {
405 first_elem = *(void **)first_elem;
406 assert(first_elem || !n_elems || !size);
407 }
408 for (i = 0; i < n_elems; i++) {
409 void *curr_elem = first_elem + size * i;
410
411 if (field->flags & VMS_ARRAY_OF_POINTER) {
412 curr_elem = *(void **)curr_elem;
413 }
414 if (!curr_elem && size) {
415 /* if null pointer check placeholder and do not follow */
416 assert(field->flags & VMS_ARRAY_OF_POINTER);
417 ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size,
418 NULL);
419 } else if (field->flags & VMS_STRUCT) {
420 ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
421 field->vmsd->version_id);
422 } else if (field->flags & VMS_VSTRUCT) {
423 ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
424 field->struct_version_id);
425 } else {
426 ret = field->info->get(f, curr_elem, size, field);
427 }
428 if (ret < 0) {
429 g_warning("Failed to load %s:%s", vmsd->name, field->name);
430 return ret;
431 }
432 }
433 } else if (field->flags & VMS_MUST_EXIST) {
434 g_warning("Input validation failed: %s/%s", vmsd->name,
435 field->name);
436 return -1;
437 }
438 field++;
439 }
440 if (vmsd->post_load) {
441 ret = vmsd->post_load(opaque, version_id);
442 }
443 return ret;
444 }
+0
-391
vendor/libslirp/src/vmstate.h less more
0 /* SPDX-License-Identifier: BSD-3-Clause */
1 /*
2 * QEMU migration/snapshot declarations
3 *
4 * Copyright (c) 2009-2011 Red Hat, Inc.
5 *
6 * Original author: Juan Quintela <quintela@redhat.com>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 *
21 * 3. Neither the name of the copyright holder nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
36 * OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38 #ifndef VMSTATE_H_
39 #define VMSTATE_H_
40
41 #include <unistd.h>
42 #include <stdint.h>
43 #include <stdbool.h>
44 #include "slirp.h"
45 #include "stream.h"
46
47 #define stringify(s) tostring(s)
48 #define tostring(s) #s
49
50 typedef struct VMStateInfo VMStateInfo;
51 typedef struct VMStateDescription VMStateDescription;
52 typedef struct VMStateField VMStateField;
53
54 int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
55 void *opaque);
56 int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
57 void *opaque, int version_id);
58
59 /* VMStateInfo allows customized migration of objects that don't fit in
60 * any category in VMStateFlags. Additional information is always passed
61 * into get and put in terms of field and vmdesc parameters. However
62 * these two parameters should only be used in cases when customized
63 * handling is needed, such as QTAILQ. For primitive data types such as
64 * integer, field and vmdesc parameters should be ignored inside get/put.
65 */
66 struct VMStateInfo {
67 const char *name;
68 int (*get)(SlirpIStream *f, void *pv, size_t size,
69 const VMStateField *field);
70 int (*put)(SlirpOStream *f, void *pv, size_t size,
71 const VMStateField *field);
72 };
73
74 enum VMStateFlags {
75 /* Ignored */
76 VMS_SINGLE = 0x001,
77
78 /* The struct member at opaque + VMStateField.offset is a pointer
79 * to the actual field (e.g. struct a { uint8_t *b;
80 * }). Dereference the pointer before using it as basis for
81 * further pointer arithmetic (see e.g. VMS_ARRAY). Does not
82 * affect the meaning of VMStateField.num_offset or
83 * VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for
84 * those. */
85 VMS_POINTER = 0x002,
86
87 /* The field is an array of fixed size. VMStateField.num contains
88 * the number of entries in the array. The size of each entry is
89 * given by VMStateField.size and / or opaque +
90 * VMStateField.size_offset; see VMS_VBUFFER and
91 * VMS_MULTIPLY. Each array entry will be processed individually
92 * (VMStateField.info.get()/put() if VMS_STRUCT is not set,
93 * recursion into VMStateField.vmsd if VMS_STRUCT is set). May not
94 * be combined with VMS_VARRAY*. */
95 VMS_ARRAY = 0x004,
96
97 /* The field is itself a struct, containing one or more
98 * fields. Recurse into VMStateField.vmsd. Most useful in
99 * combination with VMS_ARRAY / VMS_VARRAY*, recursing into each
100 * array entry. */
101 VMS_STRUCT = 0x008,
102
103 /* The field is an array of variable size. The int32_t at opaque +
104 * VMStateField.num_offset contains the number of entries in the
105 * array. See the VMS_ARRAY description regarding array handling
106 * in general. May not be combined with VMS_ARRAY or any other
107 * VMS_VARRAY*. */
108 VMS_VARRAY_INT32 = 0x010,
109
110 /* Ignored */
111 VMS_BUFFER = 0x020,
112
113 /* The field is a (fixed-size or variable-size) array of pointers
114 * (e.g. struct a { uint8_t *b[]; }). Dereference each array entry
115 * before using it. Note: Does not imply any one of VMS_ARRAY /
116 * VMS_VARRAY*; these need to be set explicitly. */
117 VMS_ARRAY_OF_POINTER = 0x040,
118
119 /* The field is an array of variable size. The uint16_t at opaque
120 * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
121 * contains the number of entries in the array. See the VMS_ARRAY
122 * description regarding array handling in general. May not be
123 * combined with VMS_ARRAY or any other VMS_VARRAY*. */
124 VMS_VARRAY_UINT16 = 0x080,
125
126 /* The size of the individual entries (a single array entry if
127 * VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if
128 * neither is set) is variable (i.e. not known at compile-time),
129 * but the same for all entries. Use the int32_t at opaque +
130 * VMStateField.size_offset (subject to VMS_MULTIPLY) to determine
131 * the size of each (and every) entry. */
132 VMS_VBUFFER = 0x100,
133
134 /* Multiply the entry size given by the int32_t at opaque +
135 * VMStateField.size_offset (see VMS_VBUFFER description) with
136 * VMStateField.size to determine the number of bytes to be
137 * allocated. Only valid in combination with VMS_VBUFFER. */
138 VMS_MULTIPLY = 0x200,
139
140 /* The field is an array of variable size. The uint8_t at opaque +
141 * VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
142 * contains the number of entries in the array. See the VMS_ARRAY
143 * description regarding array handling in general. May not be
144 * combined with VMS_ARRAY or any other VMS_VARRAY*. */
145 VMS_VARRAY_UINT8 = 0x400,
146
147 /* The field is an array of variable size. The uint32_t at opaque
148 * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
149 * contains the number of entries in the array. See the VMS_ARRAY
150 * description regarding array handling in general. May not be
151 * combined with VMS_ARRAY or any other VMS_VARRAY*. */
152 VMS_VARRAY_UINT32 = 0x800,
153
154 /* Fail loading the serialised VM state if this field is missing
155 * from the input. */
156 VMS_MUST_EXIST = 0x1000,
157
158 /* When loading serialised VM state, allocate memory for the
159 * (entire) field. Only valid in combination with
160 * VMS_POINTER. Note: Not all combinations with other flags are
161 * currently supported, e.g. VMS_ALLOC|VMS_ARRAY_OF_POINTER won't
162 * cause the individual entries to be allocated. */
163 VMS_ALLOC = 0x2000,
164
165 /* Multiply the number of entries given by the integer at opaque +
166 * VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num
167 * to determine the number of entries in the array. Only valid in
168 * combination with one of VMS_VARRAY*. */
169 VMS_MULTIPLY_ELEMENTS = 0x4000,
170
171 /* A structure field that is like VMS_STRUCT, but uses
172 * VMStateField.struct_version_id to tell which version of the
173 * structure we are referencing to use. */
174 VMS_VSTRUCT = 0x8000,
175 };
176
177 struct VMStateField {
178 const char *name;
179 size_t offset;
180 size_t size;
181 size_t start;
182 int num;
183 size_t num_offset;
184 size_t size_offset;
185 const VMStateInfo *info;
186 enum VMStateFlags flags;
187 const VMStateDescription *vmsd;
188 int version_id;
189 int struct_version_id;
190 bool (*field_exists)(void *opaque, int version_id);
191 };
192
193 struct VMStateDescription {
194 const char *name;
195 int version_id;
196 int (*pre_load)(void *opaque);
197 int (*post_load)(void *opaque, int version_id);
198 int (*pre_save)(void *opaque);
199 VMStateField *fields;
200 };
201
202
203 extern const VMStateInfo slirp_vmstate_info_int16;
204 extern const VMStateInfo slirp_vmstate_info_int32;
205 extern const VMStateInfo slirp_vmstate_info_uint8;
206 extern const VMStateInfo slirp_vmstate_info_uint16;
207 extern const VMStateInfo slirp_vmstate_info_uint32;
208
209 /** Put this in the stream when migrating a null pointer.*/
210 #define VMS_NULLPTR_MARKER (0x30U) /* '0' */
211 extern const VMStateInfo slirp_vmstate_info_nullptr;
212
213 extern const VMStateInfo slirp_vmstate_info_buffer;
214 extern const VMStateInfo slirp_vmstate_info_tmp;
215
216 #define type_check_array(t1, t2, n) ((t1(*)[n])0 - (t2 *)0)
217 #define type_check_pointer(t1, t2) ((t1 **)0 - (t2 *)0)
218 #define typeof_field(type, field) typeof(((type *)0)->field)
219 #define type_check(t1, t2) ((t1 *)0 - (t2 *)0)
220
221 #define vmstate_offset_value(_state, _field, _type) \
222 (offsetof(_state, _field) + type_check(_type, typeof_field(_state, _field)))
223
224 #define vmstate_offset_pointer(_state, _field, _type) \
225 (offsetof(_state, _field) + \
226 type_check_pointer(_type, typeof_field(_state, _field)))
227
228 #define vmstate_offset_array(_state, _field, _type, _num) \
229 (offsetof(_state, _field) + \
230 type_check_array(_type, typeof_field(_state, _field), _num))
231
232 #define vmstate_offset_buffer(_state, _field) \
233 vmstate_offset_array(_state, _field, uint8_t, \
234 sizeof(typeof_field(_state, _field)))
235
236 /* In the macros below, if there is a _version, that means the macro's
237 * field will be processed only if the version being received is >=
238 * the _version specified. In general, if you add a new field, you
239 * would increment the structure's version and put that version
240 * number into the new field so it would only be processed with the
241 * new version.
242 *
243 * In particular, for VMSTATE_STRUCT() and friends the _version does
244 * *NOT* pick the version of the sub-structure. It works just as
245 * specified above. The version of the top-level structure received
246 * is passed down to all sub-structures. This means that the
247 * sub-structures must have version that are compatible with all the
248 * structures that use them.
249 *
250 * If you want to specify the version of the sub-structure, use
251 * VMSTATE_VSTRUCT(), which allows the specific sub-structure version
252 * to be directly specified.
253 */
254
255 #define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) \
256 { \
257 .name = (stringify(_field)), .version_id = (_version), \
258 .field_exists = (_test), .size = sizeof(_type), .info = &(_info), \
259 .flags = VMS_SINGLE, \
260 .offset = vmstate_offset_value(_state, _field, _type), \
261 }
262
263 #define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) \
264 { \
265 .name = (stringify(_field)), .version_id = (_version), .num = (_num), \
266 .info = &(_info), .size = sizeof(_type), .flags = VMS_ARRAY, \
267 .offset = vmstate_offset_array(_state, _field, _type, _num), \
268 }
269
270 #define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) \
271 { \
272 .name = (stringify(_field)), .version_id = (_version), \
273 .field_exists = (_test), .vmsd = &(_vmsd), .size = sizeof(_type), \
274 .flags = VMS_STRUCT, \
275 .offset = vmstate_offset_value(_state, _field, _type), \
276 }
277
278 #define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) \
279 { \
280 .name = (stringify(_field)), .version_id = (_version), \
281 .vmsd = &(_vmsd), .size = sizeof(_type *), \
282 .flags = VMS_STRUCT | VMS_POINTER, \
283 .offset = vmstate_offset_pointer(_state, _field, _type), \
284 }
285
286 #define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, \
287 _vmsd, _type) \
288 { \
289 .name = (stringify(_field)), .num = (_num), .field_exists = (_test), \
290 .version_id = (_version), .vmsd = &(_vmsd), .size = sizeof(_type), \
291 .flags = VMS_STRUCT | VMS_ARRAY, \
292 .offset = vmstate_offset_array(_state, _field, _type, _num), \
293 }
294
295 #define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) \
296 { \
297 .name = (stringify(_field)), .version_id = (_version), \
298 .field_exists = (_test), .size = (_size - _start), \
299 .info = &slirp_vmstate_info_buffer, .flags = VMS_BUFFER, \
300 .offset = vmstate_offset_buffer(_state, _field) + _start, \
301 }
302
303 #define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) \
304 { \
305 .name = (stringify(_field)), .version_id = (_version), \
306 .field_exists = (_test), \
307 .size_offset = vmstate_offset_value(_state, _field_size, uint32_t), \
308 .info = &slirp_vmstate_info_buffer, \
309 .flags = VMS_VBUFFER | VMS_POINTER, \
310 .offset = offsetof(_state, _field), \
311 }
312
313 #define QEMU_BUILD_BUG_ON_STRUCT(x) \
314 struct { \
315 int : (x) ? -1 : 1; \
316 }
317
318 #define QEMU_BUILD_BUG_ON_ZERO(x) \
319 (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)))
320
321 /* Allocate a temporary of type 'tmp_type', set tmp->parent to _state
322 * and execute the vmsd on the temporary. Note that we're working with
323 * the whole of _state here, not a field within it.
324 * We compile time check that:
325 * That _tmp_type contains a 'parent' member that's a pointer to the
326 * '_state' type
327 * That the pointer is right at the start of _tmp_type.
328 */
329 #define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) \
330 { \
331 .name = "tmp", \
332 .size = sizeof(_tmp_type) + \
333 QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \
334 type_check_pointer(_state, typeof_field(_tmp_type, parent)), \
335 .vmsd = &(_vmsd), .info = &slirp_vmstate_info_tmp, \
336 }
337
338 #define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
339 VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
340
341 #define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
342 VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
343
344 #define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \
345 VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type)
346
347 #define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
348 VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, _vmsd, \
349 _type)
350
351 #define VMSTATE_INT16_V(_f, _s, _v) \
352 VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int16, int16_t)
353 #define VMSTATE_INT32_V(_f, _s, _v) \
354 VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int32, int32_t)
355
356 #define VMSTATE_UINT8_V(_f, _s, _v) \
357 VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint8, uint8_t)
358 #define VMSTATE_UINT16_V(_f, _s, _v) \
359 VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint16, uint16_t)
360 #define VMSTATE_UINT32_V(_f, _s, _v) \
361 VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint32, uint32_t)
362
363 #define VMSTATE_INT16(_f, _s) VMSTATE_INT16_V(_f, _s, 0)
364 #define VMSTATE_INT32(_f, _s) VMSTATE_INT32_V(_f, _s, 0)
365
366 #define VMSTATE_UINT8(_f, _s) VMSTATE_UINT8_V(_f, _s, 0)
367 #define VMSTATE_UINT16(_f, _s) VMSTATE_UINT16_V(_f, _s, 0)
368 #define VMSTATE_UINT32(_f, _s) VMSTATE_UINT32_V(_f, _s, 0)
369
370 #define VMSTATE_UINT16_TEST(_f, _s, _t) \
371 VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint16, uint16_t)
372
373 #define VMSTATE_UINT32_TEST(_f, _s, _t) \
374 VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint32, uint32_t)
375
376 #define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \
377 VMSTATE_ARRAY(_f, _s, _n, _v, slirp_vmstate_info_int16, int16_t)
378
379 #define VMSTATE_INT16_ARRAY(_f, _s, _n) VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
380
381 #define VMSTATE_BUFFER_V(_f, _s, _v) \
382 VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
383
384 #define VMSTATE_BUFFER(_f, _s) VMSTATE_BUFFER_V(_f, _s, 0)
385
386 #define VMSTATE_END_OF_LIST() \
387 { \
388 }
389
390 #endif
00 /*
11 SPDX-License-Identifier: MIT
22
3 Parson ( http://kgabis.github.com/parson/ )
3 Parson 1.0.2 ( http://kgabis.github.com/parson/ )
44 Copyright (c) 2012 - 2019 Krzysztof Gabis
55
66 Permission is hereby granted, free of charge, to any person obtaining a copy
155155 return NULL;
156156 }
157157 output_string[n] = '\0';
158 strncpy(output_string, string, n);
158 memcpy(output_string, string, n);
159159 return output_string;
160160 }
161161
14951495 size_t json_serialization_size(const JSON_Value *value) {
14961496 char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
14971497 int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf);
1498 return res < 0 ? 0 : (size_t)(res + 1);
1498 return res < 0 ? 0 : (size_t)(res) + 1;
14991499 }
15001500
15011501 JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
15551555 size_t json_serialization_size_pretty(const JSON_Value *value) {
15561556 char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
15571557 int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf);
1558 return res < 0 ? 0 : (size_t)(res + 1);
1558 return res < 0 ? 0 : (size_t)(res) + 1;
15591559 }
15601560
15611561 JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
17751775 }
17761776
17771777 JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) {
1778 return json_object_set_value(object, name, json_value_init_string(string));
1778 JSON_Value *value = json_value_init_string(string);
1779 JSON_Status status = json_object_set_value(object, name, value);
1780 if (status == JSONFailure) {
1781 json_value_free(value);
1782 }
1783 return status;
17791784 }
17801785
17811786 JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
1782 return json_object_set_value(object, name, json_value_init_number(number));
1787 JSON_Value *value = json_value_init_number(number);
1788 JSON_Status status = json_object_set_value(object, name, value);
1789 if (status == JSONFailure) {
1790 json_value_free(value);
1791 }
1792 return status;
17831793 }
17841794
17851795 JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) {
1786 return json_object_set_value(object, name, json_value_init_boolean(boolean));
1796 JSON_Value *value = json_value_init_boolean(boolean);
1797 JSON_Status status = json_object_set_value(object, name, value);
1798 if (status == JSONFailure) {
1799 json_value_free(value);
1800 }
1801 return status;
17871802 }
17881803
17891804 JSON_Status json_object_set_null(JSON_Object *object, const char *name) {
1790 return json_object_set_value(object, name, json_value_init_null());
1805 JSON_Value *value = json_value_init_null();
1806 JSON_Status status = json_object_set_value(object, name, value);
1807 if (status == JSONFailure) {
1808 json_value_free(value);
1809 }
1810 return status;
17911811 }
17921812
17931813 JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
00 /*
11 SPDX-License-Identifier: MIT
22
3 Parson ( http://kgabis.github.com/parson/ )
3 Parson 1.0.2 ( http://kgabis.github.com/parson/ )
44 Copyright (c) 2012 - 2019 Krzysztof Gabis
55
66 Permission is hereby granted, free of charge, to any person obtaining a copy
+0
-27
vendor.md less more
0 # Vendor
1
2 The `*.patch` files in `vendor_patches` directory (if exists) are applied to `vendor` via [`vendor.sh`](./vendor.sh).
3 Please DO NOT edit files under `vendor`.
4
5 ## Update vendor
6
7 Steps:
8 * Update commits specified in [`vendor.sh`](./vendor.sh).
9 * Rebase `*.patch` under `vendor_patches` if needed (see below).
10 * Run [`vendor.sh`](./vendor.sh).
11
12 ## Modify `*.patch`
13
14 Please feel free to replace/add/remove `*.patch` files in `vendor_patches` directory.
15
16 Steps:
17 * Clone the upstream [libslirp](https://gitlab.freedesktop.org/slirp/libslirp) repo.
18 * Checkout `LIBSLIRP_COMMIT` specified in [`vendor.sh`](./vendor.sh)
19 * Apply patches in this directory (`git am *.patch`).
20 * Commit your own change with `Signed-off-by` line (`git commit -a -s`). See [`https://wiki.qemu.org/Contribute/SubmitAPatch#Patch_emails_must_include_a_Signed-off-by:_line`](https://wiki.qemu.org/Contribute/SubmitAPatch#Patch_emails_must_include_a_Signed-off-by:_line).
21 * Consider melding your change into existing patches if your change is trivial (`git rebase -i ...`).
22 * Run `git format-patch upstream/master` and put the new patch set into this directory.
23 * Run [`vendor.sh`](./vendor.sh).
24 * Open a PR to the slirp4netns repo.
25
26 Note: We may squash your patch to another patch but we will keep your `Signed-off-by` line.
00 #!/bin/bash
11 set -eux -o pipefail
2 # Aug 2, 2019
3 LIBSLIRP_COMMIT=76462e2f16c6fce6856fb914cbef6207d0be4bc5
4 LIBSLIRP_REPO=https://gitlab.freedesktop.org/slirp/libslirp.git
52
6 # Jul 12, 2019
7 PARSON_COMMIT=c5bb9557fe98367aa8e041c65863909f12ee76b2
3 # Feb 21, 2020
4 PARSON_COMMIT=70dc239f8f54c80bf58477b25435fd3dd3102804
85 PARSON_REPO=https://github.com/kgabis/parson.git
96
107 # prepare
1310 tmp_git=$tmp/git
1411 tmp_vendor=$tmp/vendor
1512 mkdir -p $tmp_git $tmp_vendor
16
17 # vendor libslirp
18 git clone $LIBSLIRP_REPO $tmp_git/libslirp
19 (
20 cd $tmp_git/libslirp
21 git checkout $LIBSLIRP_COMMIT
22 if ls $slirp4netns_root/vendor_patches/libslirp/*.patch >/dev/null; then
23 git am $slirp4netns_root/vendor_patches/libslirp/*.patch
24 fi
25 # run make to generate src/libslirp-version.h
26 make
27 mkdir -p $tmp_vendor/libslirp/src
28 cp -a .clang-format COPYRIGHT README.md $tmp_vendor/libslirp
29 cp -a src/{*.c,*.h} $tmp_vendor/libslirp/src
30 )
3113
3214 # vendor parson
3315 git clone $PARSON_REPO $tmp_git/parson
4325 # DO NOT EDIT MANUALLY
4426
4527 Vendored components:
46 * libslirp: $LIBSLIRP_REPO (\`$LIBSLIRP_COMMIT\`)
4728 * parson: $PARSON_REPO (\`$PARSON_COMMIT\`)
4829
4930 EOF
5031
51 if ls $slirp4netns_root/vendor_patches/libslirp/*.patch >/dev/null; then
52 cat <<EOF >>$tmp_vendor/README.md
53 Applied patches (sha256sum):
54 \`\`\`
55 $(
56 cd $slirp4netns_root
57 sha256sum vendor_patches/*/*
58 )
59 \`\`\`
60
61 EOF
62 fi
63
6432 cat <<EOF >>$tmp_vendor/README.md
6533 Please do not edit the contents under this directory manually.
6634
67 See also [\`../vendor.md\`](../vendor.md).
35 Use [\`../vendor.sh\`](../vendor.sh) to update the contents.
6836 EOF
6937
7038 # fix up