From e97918417e2f91e76024bee546366f2f0d43c281 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 19 Nov 2006 17:25:11 +0000 Subject: [PATCH] Break up the old chbind into ncontext, nattribute, and naddress. This is done mostly to add support for network flags and caps, but also to get the same level of flexibility that the security contexts have. In addition, a vc_nidopt2nid was created to correctly map --nid self to the current process's nid. git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@2384 94cd875c-1c1d-0410-91d2-eb244daf1a30 --- contrib/manifest.dat.pathsubst | 4 + ensc_wrappers/wrappers-vserver.hc | 58 +++++ lib/Makefile-files | 3 +- lib/nidopt2nid.c | 40 ++++ lib/vserver.h | 2 + scripts/Makefile-files | 3 +- scripts/chbind | 130 +++++++++++ scripts/util-vserver-vars.pathsubst | 4 + src/Makefile-files | 32 ++- src/chbind.c | 2 +- src/naddress.c | 416 ++++++++++++++++++++++++++++++++++++ src/nattribute.c | 179 ++++++++++++++++ src/ncontext.c | 293 +++++++++++++++++++++++++ 13 files changed, 1156 insertions(+), 10 deletions(-) create mode 100644 lib/nidopt2nid.c create mode 100755 scripts/chbind create mode 100644 src/naddress.c create mode 100644 src/nattribute.c create mode 100644 src/ncontext.c diff --git a/contrib/manifest.dat.pathsubst b/contrib/manifest.dat.pathsubst index 0fe2a58..0fbdc08 100644 --- a/contrib/manifest.dat.pathsubst +++ b/contrib/manifest.dat.pathsubst @@ -46,6 +46,7 @@ build @PKGLIBDIR@/defaults/debootstrap.uri base @PKGLIBDIR@/capchroot base @PKGLIBDIR@/chain-echo core @PKGLIBDIR@/chcontext-compat +core @PKGLIBDIR@/chbind-compat base @PKGLIBDIR@/check-unixfile base @PKGLIBDIR@/chroot-sh base @PKGLIBDIR@/exec-ulimit @@ -83,6 +84,9 @@ core @SBINDIR@/chcontext core @SBINDIR@/chxid base @SBINDIR@/exec-cd core @SBINDIR@/lsxid +core @SBINDIR@/naddress +core @SBINDIR@/nattribute +core @SBINDIR@/ncontext core @SBINDIR@/reducecap core @SBINDIR@/setattr core @SBINDIR@/showattr diff --git a/ensc_wrappers/wrappers-vserver.hc b/ensc_wrappers/wrappers-vserver.hc index 0c59a8c..488d57d 100644 --- a/ensc_wrappers/wrappers-vserver.hc +++ b/ensc_wrappers/wrappers-vserver.hc @@ -40,6 +40,14 @@ Evc_get_task_xid(pid_t pid) return res; } +inline static WRAPPER_DECL nid_t +Evc_get_task_nid(pid_t pid) +{ + register nid_t res = vc_get_task_nid(pid); + FatalErrnoError(res==VC_NOCTX, "vc_get_task_nid()"); + return res; +} + inline static WRAPPER_DECL xid_t Evc_ctx_create(xid_t xid) { @@ -48,6 +56,14 @@ Evc_ctx_create(xid_t xid) return res; } +inline static WRAPPER_DECL nid_t +Evc_net_create(nid_t nid) +{ + register nid_t res = vc_net_create(nid); + FatalErrnoError(res==VC_NOCTX, "vc_net_create()"); + return res; +} + inline static WRAPPER_DECL void Evc_ctx_migrate(xid_t xid) { @@ -55,6 +71,12 @@ Evc_ctx_migrate(xid_t xid) } inline static WRAPPER_DECL void +Evc_net_migrate(nid_t nid) +{ + FatalErrnoError(vc_net_migrate(nid)==-1, "vc_net_migrate()"); +} + +inline static WRAPPER_DECL void Evc_get_cflags(xid_t xid, struct vc_ctx_flags *flags) { FatalErrnoError(vc_get_cflags(xid, flags)==-1, "vc_get_cflags()"); @@ -67,6 +89,18 @@ Evc_set_cflags(xid_t xid, struct vc_ctx_flags const *flags) } inline static WRAPPER_DECL void +Evc_get_nflags(nid_t nid, struct vc_net_flags *flags) +{ + FatalErrnoError(vc_get_nflags(nid, flags)==-1, "vc_get_nflags()"); +} + +inline static WRAPPER_DECL void +Evc_set_nflags(nid_t nid, struct vc_net_flags const *flags) +{ + FatalErrnoError(vc_set_nflags(nid, flags)==-1, "vc_set_nflags()"); +} + +inline static WRAPPER_DECL void Evc_set_vhi_name(xid_t xid, vc_uts_type type, char const *val, size_t len) { @@ -86,6 +120,18 @@ Evc_set_ccaps(xid_t xid, struct vc_ctx_caps const *caps) } inline static WRAPPER_DECL void +Evc_get_ncaps(nid_t nid, struct vc_net_caps *caps) +{ + FatalErrnoError(vc_get_ncaps(nid, caps)==-1, "vc_get_ncaps()"); +} + +inline static WRAPPER_DECL void +Evc_set_ncaps(nid_t nid, struct vc_net_caps const *caps) +{ + FatalErrnoError(vc_set_ncaps(nid, caps)==-1, "vc_set_ncaps()"); +} + +inline static WRAPPER_DECL void Evc_set_namespace() { FatalErrnoError(vc_set_namespace()==-1, "vc_set_namespace()"); @@ -122,3 +168,15 @@ Evc_xidopt2xid(char const *id, bool honor_static) return rc; } + +inline static WRAPPER_DECL nid_t +Evc_nidopt2nid(char const *id, bool honor_static) +{ + char const * err; + nid_t rc = vc_nidopt2nid(id, honor_static, &err); + if (__builtin_expect(rc==VC_NOCTX,0)) { + ENSC_DETAIL1(msg, "vc_nidopt2nid", id, 1); + FatalErrnoErrorFail(msg); + } + return rc; +} diff --git a/lib/Makefile-files b/lib/Makefile-files index 736d7f1..7d2c3bf 100644 --- a/lib/Makefile-files +++ b/lib/Makefile-files @@ -33,7 +33,8 @@ lib_management_SRCS = lib/comparevserverbyid.c \ lib/getvserverctx.c \ lib/getvservername.c \ lib/getvservervdir.c \ - lib/xidopt2xid.c + lib/xidopt2xid.c \ + lib/nidopt2nid.c lib_v11_SRCS = lib/syscall_rlimit.c \ lib/syscall_rlimit-v11.hc \ lib/syscall_kill.c \ diff --git a/lib/nidopt2nid.c b/lib/nidopt2nid.c new file mode 100644 index 0000000..d3fd8c6 --- /dev/null +++ b/lib/nidopt2nid.c @@ -0,0 +1,40 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "vserver.h" +#include +#include + +nid_t +vc_nidopt2nid(char const *str, bool honor_static, char const **err_info) +{ + char const * err; + nid_t res = VC_NOCTX; + + err = "vc_get_task_nid()"; + if (strcmp(str,"self")==0) res = vc_get_task_nid(0); + else res = vc_xidopt2xid(str, honor_static, &err); + + if (res==VC_NOCTX && err_info) *err_info = err; + + return res; +} diff --git a/lib/vserver.h b/lib/vserver.h index 41479fb..a265d30 100644 --- a/lib/vserver.h +++ b/lib/vserver.h @@ -855,6 +855,8 @@ extern "C" { /** Maps an xid given at '--xid' options to an xid_t */ xid_t vc_xidopt2xid(char const *, bool honor_static, char const **err_info); + /** Maps a nid given at '--nid' options to a nid_t */ + nid_t vc_nidopt2nid(char const *, bool honor_static, char const **err_info); vcCfgStyle vc_getVserverCfgStyle(char const *id); diff --git a/scripts/Makefile-files b/scripts/Makefile-files index 1dca1da..a4ddccb 100644 --- a/scripts/Makefile-files +++ b/scripts/Makefile-files @@ -82,7 +82,8 @@ scripts_legacy_src_SCRPTS = scripts/legacy/save_s_context \ scripts_legacy_gen_SCRPTS = scripts/legacy/vps scripts_legacy_src_PRGS = scripts/legacy/vserver-copy -scripts_sbin_src_PRGS = scripts/chcontext \ +scripts_sbin_src_PRGS = scripts/chbind \ + scripts/chcontext \ scripts/vapt-get \ scripts/vdispatch-conf \ scripts/vemerge \ diff --git a/scripts/chbind b/scripts/chbind new file mode 100755 index 0000000..75aa2a4 --- /dev/null +++ b/scripts/chbind @@ -0,0 +1,130 @@ +#! /bin/bash +# $Id$ + +# Copyright (C) 2004 Enrico Scholz +# Copyright (C) 2006 Daniel Hokka Zakrisson +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2 + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$_LIB_FUNCTIONS" + +function showHelp() +{ + echo \ +$"Usage: $1 [--silent] [--nid ] [--ip [/]] + [--bcast ] [--] * + +--silent + Do not print the addresses assigned. +--nid + Network context id to use. +--ip [/] + IP address to bind to. +--bcast + Broadcast address for the network context. + +Report bugs to <$PACKAGE_BUGREPORT>." + exit $2 +} + +function showVersion() +{ + echo \ +$"chbind $PACKAGE_VERSION -- bind to IP addresses and execute a program +This program is part of $PACKAGE_STRING + +Copyright (C) 2004 Enrico Scholz +Copyright (C) 2006 Daniel Hokka Zakrisson +This program is free software; you may redistribute it under the terms of +the GNU General Public License. This program has absolutely no warranty." + exit $1 +} + +$_VSERVER_INFO - FEATURE vnet || exec $_CHBIND_COMPAT "$@" + +tmp=$(getopt -o + --long ncap:,nid:,ip:,bcast:,disconnect,flag:,secure,silent,help,version -n "$0" -- "$@") || exit 1 +eval set -- "$tmp" + +OPT_CAPS=() +OPT_NID= +OPT_DISCONNECT= +OPT_FLAGS=() +OPT_SECURE= +OPT_SILENT= +OPT_BCAST= +OPT_IPS=() + +while true; do + case "$1" in + --help) showHelp $0 0;; + --version) showVersion 0;; + --ncap) OPT_CAPS=( "${OPT_CAPS[@]}" "$2" ); shift;; + --nid) OPT_NID=$2; shift;; + --disconnect) OPT_DISCONNECT=1;; + --flag) OPT_FLAGS=( "${OPT_FLAGS[@]}" "$2" ); shift;; + --secure) OPT_SECURE=1;; + --silent) OPT_SILENT=1;; + --ip) OPT_IPS=( "${OPT_IPS[@]}" "$2" ); shift;; + --bcast) OPT_BCAST=$2; shift;; + --) shift; break;; + *) echo $"chbind: internal error; arg=='$1'" >&2; exit 1;; + esac + shift +done + +create_cmd=( $_NCONTEXT --create --silentexist + ${OPT_SILENT:+--silent} + ${OPT_NID:+--nid "$OPT_NID"} ) + +chain_cmd=() + +old_IFS=$IFS +IFS=,$IFS + +chain_cmd=( "${chain_cmd[@]}" + -- + $_NATTRIBUTE --set + ${OPT_SECURE:+--secure} + ${OPT_CAPS:+--ncap "${OPT_CAPS[*]}"} + ${OPT_FLAGS:+--flag "${OPT_FLAGS[*]}"} + -- + $_NADDRESS --add + ${OPT_SILENT:+--silent} + ${OPT_BCAST:+--bcast "$OPT_BCAST"} ) + +for ip in "${OPT_IPS[@]}"; do + chain_cmd=( "${chain_cmd[@]}" --ip "$ip" ) +done + +migrate_cmd=( $_NCONTEXT + ${OPT_SILENT:+--silent} + ${OPT_DISCONNECT:+--disconnect} ) + +IFS=$old_IFS + +if test -z "$OPT_NID" || $_VSERVER_INFO -q "$OPT_NID" XIDTYPE static; then + "${create_cmd[@]}" "${chain_cmd[@]}" -- "$@" + rc=$? +else + rc=254 +fi + +test "$rc" -ne 254 || exec "${migrate_cmd[@]}" --nid "$OPT_NID" --migrate -- "$@" +exit $rc diff --git a/scripts/util-vserver-vars.pathsubst b/scripts/util-vserver-vars.pathsubst index ee7662f..4548503 100644 --- a/scripts/util-vserver-vars.pathsubst +++ b/scripts/util-vserver-vars.pathsubst @@ -31,6 +31,7 @@ __DEFAULT_VSERVERPKGDIR='@VSERVERPKGDIR@' _CAPCHROOT="$__PKGLIBDIR/capchroot" _CHAINECHO="$__PKGLIBDIR/chain-echo" _CHBIND="$__SBINDIR/chbind" +_CHBIND_COMPAT="$__PKGLIBDIR/chbind-compat" _CHCONTEXT="$__SBINDIR/chcontext" _CHCONTEXT_COMPAT="$__PKGLIBDIR/chcontext-compat" _CHECK_UNIXFILE="$__PKGLIBDIR/check-unixfile" @@ -53,6 +54,9 @@ _LIB_VSERVER_BUILD_FUNCTIONS_PKGMGMT="$__PKGLIBDIR/vserver-build.functions.pkgmg _LISTDEVIP="$__LEGACYDIR/listdevip" _LOCKFILE="$__PKGLIBDIR/lockfile" _MASK2PREFIX="$__PKGLIBDIR/mask2prefix" +_NADDRESS="$__SBINDIR/naddress" +_NATTRIBUTE="$__SBINDIR/nattribute" +_NCONTEXT="$__SBINDIR/ncontext" _PARSERPMDUMP="$__LEGACYDIR/parserpmdump" _PKGMGMT="$__PKGLIBDIR/pkgmgmt" _READLINK="$__PKGLIBDIR/readlink" diff --git a/src/Makefile-files b/src/Makefile-files index f19fa08..01f8af2 100644 --- a/src/Makefile-files +++ b/src/Makefile-files @@ -46,7 +46,7 @@ DIETPROGS += src/chcontext-compat \ src/secure-mount \ src/save_ctxinfo \ src/mask2prefix \ - src/chbind \ + src/chbind-compat \ src/exec-cd \ src/fakerunlevel \ src/keep-ctx-alive \ @@ -74,7 +74,10 @@ DIETPROGS += src/chcontext-compat \ src/vserver-info \ src/vdlimit \ src/vdu \ - src/vwait + src/vwait \ + src/ncontext \ + src/nattribute \ + src/naddress if ENSC_CAN_BEECRYPT_WITH_DIETLIBC DIETPROGS += src/vhashify @@ -110,6 +113,7 @@ pkglib_PROGRAMS += src/capchroot \ src/rpm-fake-resolver \ src/vshelper-sync \ src/sigexec \ + src/chbind-compat \ $(src_pkglib_C99_X_PROGS) \ $(src_pkglib_CXX_X_PROGS) @@ -128,8 +132,7 @@ legacy_PROGRAMS += src/ifspec \ pkglib_LTLIBRARIES += src/rpm-fake.la -sbin_PROGRAMS += src/chbind \ - src/exec-cd \ +sbin_PROGRAMS += src/exec-cd \ src/lsxid \ src/chxid \ src/vps \ @@ -148,6 +151,9 @@ sbin_PROGRAMS += src/chbind \ src/vserver-info \ src/vuname \ src/vwait \ + src/ncontext \ + src/nattribute \ + src/naddress \ $(src_sbin_CXX_X_PROGS) if ENSC_HAVE_C99_COMPILER @@ -159,9 +165,9 @@ src_capchroot_SOURCES = src/capchroot.c src_capchroot_LDADD = $(VSERVER_LDADDS) src_capchroot_LDFLAGS = $(VSERVER_LDFLGS) -src_chbind_SOURCES = src/chbind.c -src_chbind_LDADD = $(VSERVER_LDADDS) -src_chbind_LDFLAGS = $(VSERVER_LDFLGS) +src_chbind_compat_SOURCES = src/chbind.c +src_chbind_compat_LDADD = $(VSERVER_LDADDS) +src_chbind_compat_LDFLAGS = $(VSERVER_LDFLGS) src_chcontext_compat_SOURCES = src/chcontext.c src_chcontext_compat_LDADD = $(VSERVER_LDADDS) $(LIBINTERNAL) @@ -301,6 +307,18 @@ src_vwait_SOURCES = src/vwait.c src_vwait_LDADD = $(VSERVER_LDADDS) src_vwait_LDFLAGS = $(VSERVER_LDFLGS) +src_ncontext_SOURCES = src/ncontext.c +src_ncontext_LDADD = $(VSERVER_LDADDS) $(LIBINTERNAL) +src_ncontext_LDFLAGS = $(VSERVER_LDFLGS) + +src_nattribute_SOURCES = src/nattribute.c +src_nattribute_LDADD = $(VSERVER_LDADDS) +src_nattribute_LDFLAGS = $(VSERVER_LDFLGS) + +src_naddress_SOURCES = src/naddress.c +src_naddress_LDADD = $(VSERVER_LDADDS) +src_naddress_LDFLAGS = $(VSERVER_LDFLGS) + EXTRA_PROGRAMS += $(src_sbin_CXX_PROGS) $(src_pkglib_CXX_PROGS) TESTS_ENVIRONMENT += srctestsuitedir=$(top_builddir)/src/testsuite diff --git a/src/chbind.c b/src/chbind.c index 4fb628e..f017c33 100644 --- a/src/chbind.c +++ b/src/chbind.c @@ -316,7 +316,7 @@ int main (int argc, char *argv[]) case CMD_SILENT : is_silent = true; break; case CMD_BCAST : readBcast(optarg, &bcast); break; #if defined(VC_ENABLE_API_NET) - case CMD_NID : nid = Evc_xidopt2xid(optarg,true); break; + case CMD_NID : nid = Evc_nidopt2nid(optarg,true); break; #else case CMD_NID : WRITE_MSG(2, "WARNING: --nid is not supported by this version\n"); break; #endif diff --git a/src/naddress.c b/src/naddress.c new file mode 100644 index 0000000..0d1efc1 --- /dev/null +++ b/src/naddress.c @@ -0,0 +1,416 @@ +// $Id$ + +// Copyright (C) 2003 Enrico Scholz +// Copyright (C) 2006 Daniel Hokka Zakrisson +// based on chbind.cc by Jacques Gelinas +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "vserver.h" +#include "util.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENSC_WRAPPERS_PREFIX "naddress: " +#define ENSC_WRAPPERS_IO 1 +#define ENSC_WRAPPERS_UNISTD 1 +#define ENSC_WRAPPERS_VSERVER 1 +#include "wrappers.h" + +#define CMD_HELP 0x1000 +#define CMD_VERSION 0x1001 + +#define CMD_SILENT 0x2000 +#define CMD_NID 0x2001 +#define CMD_ADD 0x2002 +#define CMD_REMOVE 0x2003 +#define CMD_IP 0x2010 +#define CMD_BCAST 0x2011 + +int wrapper_exit_code = 255; + + +static struct option const +CMDLINE_OPTIONS[] = { + { "help", no_argument, 0, CMD_HELP }, + { "version", no_argument, 0, CMD_VERSION }, + { "silent", no_argument, 0, CMD_SILENT }, + { "add", no_argument, 0, CMD_ADD }, + { "remove", no_argument, 0, CMD_REMOVE }, + { "nid", required_argument, 0, CMD_NID }, + { "ip", required_argument, 0, CMD_IP }, + { "bcast", required_argument, 0, CMD_BCAST }, + { 0,0,0,0 } +}; + +struct vc_ips { + struct vc_net_nx a; + struct vc_ips *next; +}; + +struct Arguments { + nid_t nid; + struct vc_ips head; + bool is_silent; + bool do_add; + bool do_remove; +}; + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage:\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " [--silent] [--nid ] [--ip [/]] [--bcast ] [--] *\n\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "naddress " VERSION " -- bind to an ip and execute a program\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2003,2004 Enrico Scholz\n" + "Copyright (C) 2006 Daniel Hokka Zakrisson\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +/* + Check if a network device exist in /proc/net/dev. + This is used because ifconfig_ioctl triggers modprobe if requesting + information about non existant devices. + + Return != 0 if the device exist. +*/ +static bool +existsDevice(char const *dev_raw) +{ + size_t buf_size=8192; + char dev[strlen(dev_raw)+2]; + + strcpy(dev, dev_raw); + strcat(dev, ":"); + for (;;) { + char buf[buf_size]; + char * pos; + bool too_small; + int fd=open("/proc/net/dev", O_RDONLY); + + if (fd==-1) return false; + too_small = EreadAll(fd, buf, buf_size); + close(fd); + + if (too_small) { + buf_size *= 2; + continue; + } + + pos = strstr(buf, dev); + return (pos && (pos==buf || pos[-1]==' ' || pos[-1]=='\n')); + } +} + +static int ifconfig_ioctl( + int fd, + const char *ifname, + int cmd, + struct ifreq *ifr) +{ + strcpy(ifr->ifr_name, ifname); + return ioctl(fd, cmd, ifr); +} + +/* + Fetch the IP number of an interface from the kernel. + Assume the device is already available in the kernel + Return -1 if any error. +*/ +int ifconfig_getaddr ( + const char *ifname, + uint32_t *addr, + uint32_t *mask, + uint32_t *bcast) +{ + int ret = -1; + if (existsDevice(ifname)){ + int skfd = socket(AF_INET, SOCK_DGRAM, 0); + if (skfd != -1){ + struct ifreq ifr; + if (addr != NULL && ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){ + struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr; + *addr = sin->sin_addr.s_addr; + ret = 0; + } + if (mask != NULL && ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){ + struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr; + *mask = sin->sin_addr.s_addr; + ret = 0; + } + if (bcast != NULL && ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){ + struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr; + *bcast = sin->sin_addr.s_addr; + ret = 0; + } + close (skfd); + } + } + return ret; +} + +static int +convertAddress(const char *str, vc_net_nx_type *type, void *dst) +{ + int ret; + if (type) *type = vcNET_IPV4; + ret = inet_pton(AF_INET, str, dst); + if (ret==0) { + if (type) *type = vcNET_IPV6; + ret = inet_pton(AF_INET6, str, dst); + } + return ret > 0 ? 0 : -1; +} + +static void +readIP(char const *str, struct vc_ips **ips) +{ + if (ifconfig_getaddr(str, &(*ips)->a.ip[0], &(*ips)->a.mask[0], NULL)==-1) { + char *pt; + char tmpopt[strlen(str)+1]; + uint32_t *mask = (*ips)->a.mask; + + strcpy(tmpopt,str); + pt = strchr(tmpopt,'/'); + if (pt) + *pt++ = '\0'; + + if (convertAddress(tmpopt, &(*ips)->a.type, (*ips)->a.ip) == -1) { + WRITE_MSG(2, "Invalid IP number '"); + WRITE_STR(2, tmpopt); + WRITE_MSG(2, "'\n"); + exit(wrapper_exit_code); + } + + if (pt==0) { + switch ((*ips)->a.type) { + case vcNET_IPV4: + mask[0] = htonl(0xffffff00); + break; + case vcNET_IPV6: + mask[0] = 64; + break; + default: break; + } + } + else { + // Ok, we have a network size, not a netmask + if (strchr(pt,'.')==0 && strchr(pt,':')==0) { + int sz = atoi(pt); + switch ((*ips)->a.type) { + case vcNET_IPV4: + mask[0] = htonl((1 << sz) - 1); + break; + case vcNET_IPV6: + mask[0] = sz; + break; + default: break; + } + } + else { + if (convertAddress(pt, NULL, &(*ips)->a.mask) == -1) { + WRITE_MSG(2, "Invalid netmask '"); + WRITE_STR(2, pt); + WRITE_MSG(2, "'\n"); + exit(wrapper_exit_code); + } + } + } + } + else + (*ips)->a.type = vcNET_IPV4; + + (*ips)->a.count = 1; + (*ips)->next = calloc(1, sizeof(struct vc_ips)); + *ips = (*ips)->next; +} + +static void +readBcast(char const *str, struct vc_ips **ips) +{ + uint32_t bcast; + if (ifconfig_getaddr(str, NULL, NULL, &bcast)==-1){ + if (convertAddress(str, NULL, &bcast) == -1) { + WRITE_MSG(2, "Invalid broadcast number '"); + WRITE_STR(2, optarg); + WRITE_MSG(2, "'\n"); + exit(wrapper_exit_code); + } + } + (*ips)->a.ip[0] = bcast; + (*ips)->a.count = 1; + (*ips)->a.type = vcNET_IPV4B; + (*ips)->next = calloc(1, sizeof(struct vc_ips)); + *ips = (*ips)->next; +} + +static void +tellAddress(struct vc_net_nx *addr, bool silent) +{ + char buf[41]; + if (silent) + return; + if (inet_ntop(addr->type == vcNET_IPV6 ? AF_INET6 : AF_INET, + &addr->ip, buf, sizeof(buf)) == NULL) { + WRITE_MSG(1, " "); + return; + } + WRITE_MSG(1, " "); + WRITE_STR(1, buf); +} + +static inline void +doit(struct Arguments *args) +{ + struct vc_ips *ips; + if (args->do_add) { + if (!args->is_silent) + WRITE_MSG(1, "Adding"); + for (ips = &args->head; ips->next; ips = ips->next) { + tellAddress(&ips->a, args->is_silent); + if (vc_net_add(args->nid, &ips->a) != (int)ips->a.count) { + perror(ENSC_WRAPPERS_PREFIX "vc_net_add()"); + exit(wrapper_exit_code); + } + } + if (!args->is_silent) + WRITE_MSG(1, "\n"); + } + else if (args->do_remove) { + if (!args->is_silent) + WRITE_MSG(1, "Removing"); + for (ips = &args->head; ips->next; ips = ips->next) { + tellAddress(&ips->a, args->is_silent); + if (vc_net_remove(args->nid, &ips->a) != (int)ips->a.count) { + perror(ENSC_WRAPPERS_PREFIX "vc_net_remove()"); + exit(wrapper_exit_code); + } + } + if (!args->is_silent) + WRITE_MSG(1, "\n"); + } +} + +int main (int argc, char *argv[]) +{ + struct Arguments args = { + .nid = VC_NOCTX, + .is_silent = false, + .do_add = false, + .do_remove = false, + .head = { .next = NULL }, + }; + struct vc_ips *ips = &args.head; + + while (1) { + int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0); + if (c==-1) break; + + switch (c) { + case CMD_HELP : showHelp(1, argv[0], 0); + case CMD_VERSION : showVersion(); + case CMD_SILENT : args.is_silent = true; break; + case CMD_BCAST : readBcast(optarg, &ips); break; + case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break; + case CMD_ADD : args.do_add = true; break; + case CMD_REMOVE : args.do_remove = true; break; + case CMD_IP : readIP(optarg, &ips); break; + default : + WRITE_MSG(2, "Try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help\" for more information.\n"); + exit(wrapper_exit_code); + break; + } + } + + if (args.nid == VC_NOCTX) args.nid = Evc_get_task_nid(0); + + if (!args.do_add && !args.do_remove) { + WRITE_MSG(2, "No operation specified; try '--help' for more information\n"); + exit(wrapper_exit_code); + } + else if (args.do_add && args.do_remove) { + WRITE_MSG(2, "Multiple operations specified; try '--help' for more information\n"); + exit(wrapper_exit_code); + } + + doit(&args); + + if (optind != argc) + Eexecvp (argv[optind],argv+optind); + return EXIT_SUCCESS; +} + +#ifdef ENSC_TESTSUITE +#include + +void test() +{ + struct vc_ip_mask_pair ip; + uint32_t bcast; + + bcast = 0; + readIP("1.2.3.4", &ip, &bcast); + assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffffff00) && bcast==0); + + readIP("1.2.3.4/8", &ip, &bcast); + assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xff000000) && bcast==0); + + readIP("1.2.3.4/255.255.0.0", &ip, &bcast); + assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffff0000) && bcast==0); + + readIP("localhost", &ip, &bcast); + assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xffffff00) && bcast==0); + +#if 0 + if (ifconfig_getaddr("lo", &tmp, &tmp, &tmp)!=-1) { + readIP("lo", &ip, &bcast); + assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xff000000) && bcast==ntohl(0x7fffffff)); + } +#endif +} +#endif diff --git a/src/nattribute.c b/src/nattribute.c new file mode 100644 index 0000000..5199525 --- /dev/null +++ b/src/nattribute.c @@ -0,0 +1,179 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// Copyright (C) 2006 Daniel Hokka Zakrisson +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "util.h" +#include + +#include +#include +#include + +#define ENSC_WRAPPERS_PREFIX "nattribute: " +#define ENSC_WRAPPERS_VSERVER 1 +#define ENSC_WRAPPERS_UNISTD 1 +#include + +#define CMD_HELP 0x1000 +#define CMD_VERSION 0x1001 +#define CMD_NID 0x2000 +#define CMD_SET 0x2001 +#define CMD_CAP 0x2002 +#define CMD_FLAG 0x2003 +#define CMD_SECURE 0x2004 + +int wrapper_exit_code = 1; + +struct option const +CMDLINE_OPTIONS[] = { + { "help", no_argument, 0, CMD_HELP }, + { "version", no_argument, 0, CMD_VERSION }, + { "nid", required_argument, 0, CMD_NID }, + { "set", no_argument, 0, CMD_SET }, + { "ncap", required_argument, 0, CMD_CAP }, + { "flag", required_argument, 0, CMD_FLAG }, + { "secure", no_argument, 0, CMD_SECURE }, + {0,0,0,0} +}; + +struct Arguments { + nid_t nid; + struct vc_net_flags flags; + struct vc_net_caps caps; +}; + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage:\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " --set [--nid ] [--ncap [~!]] [--flag [~!]] [--secure] -- [ *]\n" + "\n" + " --ncap ... network capability to be added\n" + " --flag ... network flag to be added\n" + "\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "nattribute " VERSION " -- sets attributes of network contexts\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2004 Enrico Scholz\n" + "Copyright (C) 2006 Daniel Hokka Zakrisson\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +static void +parseFlags(char const *str, struct vc_net_flags *flags) +{ + struct vc_err_listparser err; + int rc; + + rc = vc_list2nflag(str, 0, &err, flags); + + if (rc==-1) { + WRITE_MSG(2, "Unknown flag '"); + Vwrite(2, err.ptr, err.len); + WRITE_MSG(2, "'\n"); + exit(wrapper_exit_code); + } +} + +static void +parseNCaps(char const *str, struct vc_net_caps *caps) +{ + struct vc_err_listparser err; + int rc; + + rc = vc_list2ncap(str,0, &err, caps); + + if (rc==-1) { + WRITE_MSG(2, "Unknown ncap '"); + Vwrite(2, err.ptr, err.len); + WRITE_MSG(2, "'\n"); + exit(wrapper_exit_code); + } +} + +static void +parseSecure(struct vc_net_flags * flags, + struct vc_net_caps * caps) +{ + // TODO: generalize this + caps->ncaps = 0ull; + caps->cmask = 0ull; + + flags->flagword = 0ull; + flags->mask = 0ull; +} + +int main(int argc, char *argv[]) +{ + struct Arguments args = { + .nid = VC_NOCTX, + .flags = { .flagword = 0, .mask = 0 }, + .caps = { .ncaps = 0, .cmask = 0 }, + }; + + while (1) { + int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0); + if (c==-1) break; + + switch (c) { + case CMD_HELP : showHelp(1, argv[0], 0); + case CMD_VERSION : showVersion(); + case CMD_SET : break; // default op currently + case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break; + case CMD_FLAG : parseFlags(optarg, &args.flags); break; + case CMD_CAP : parseNCaps(optarg, &args.caps); break; + case CMD_SECURE : parseSecure(&args.flags, &args.caps); break; + default : + WRITE_MSG(2, "Try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help\" for more information.\n"); + return 255; + break; + } + } + + if (args.nid==VC_NOCTX) args.nid = Evc_get_task_nid(0); + + if (args.caps.cmask && + vc_set_ncaps(args.nid, &args.caps)==-1) + perror(ENSC_WRAPPERS_PREFIX "vc_set_ncaps()"); + else if (args.flags.mask && + vc_set_nflags(args.nid, &args.flags)==-1) + perror(ENSC_WRAPPERS_PREFIX "vc_set_nflags()"); + else if (optind +// Copyright (C) 2006 Daniel Hokka Zakrisson +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "util.h" +#include "lib/internal.h" +#include "lib_internal/util.h" +#include "lib_internal/jail.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define ENSC_WRAPPERS_PREFIX "ncontext: " +#define ENSC_WRAPPERS_UNISTD 1 +#define ENSC_WRAPPERS_VSERVER 1 +#define ENSC_WRAPPERS_FCNTL 1 +#define ENSC_WRAPPERS_SOCKET 1 +#define ENSC_WRAPPERS_IOSOCK 1 +#include + +#define CMD_HELP 0x1000 +#define CMD_VERSION 0x1001 +#define CMD_NID 0x4000 +#define CMD_CREATE 0x4001 +#define CMD_MIGRATE 0x4002 +#define CMD_DISCONNECT 0x4003 +#define CMD_SILENT 0x4004 +#define CMD_SYNCSOCK 0x4005 +#define CMD_SYNCMSG 0x4006 +#define CMD_MIGRATESELF 0x4007 +#define CMD_SILENTEXIST 0x4008 + + +struct option const +CMDLINE_OPTIONS[] = { + { "help", no_argument, 0, CMD_HELP }, + { "version", no_argument, 0, CMD_VERSION }, + { "nid", required_argument, 0, CMD_NID }, + { "create", no_argument, 0, CMD_CREATE }, + { "migrate", no_argument, 0, CMD_MIGRATE }, + { "migrate-self", no_argument, 0, CMD_MIGRATESELF }, + { "disconnect", no_argument, 0, CMD_DISCONNECT }, + { "silent", no_argument, 0, CMD_SILENT }, + { "silentexist", no_argument, 0, CMD_SILENTEXIST }, + { "syncsock", required_argument, 0, CMD_SYNCSOCK }, + { "syncmsg", required_argument, 0, CMD_SYNCMSG }, + { 0,0,0,0 }, +}; + +struct Arguments { + bool do_create; + bool do_migrate; + bool do_migrateself; + bool do_disconnect; + bool is_silentexist; + int verbosity; + nid_t nid; + char const * sync_sock; + char const * sync_msg; +}; + +int wrapper_exit_code = 255; + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage:\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " --create [--nid ] * [--] *\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " [(--migrate --nid )|--migrate-self] * [--] *\n" + "\n" + " can be:\n" + " --disconnect ... start program in background\n" + " --silent ... be silent\n" + " --silentexist ... be silent when context exists already; useful\n" + " for '--create' only\n" + " --syncsock \n" + " ... before executing the program, send a message\n" + " to the socket and wait until it closes.\n" + " must be a SOCK_STREAM unix socket\n" + " --syncmsg \n" + " ... use as synchronization message; by\n" + " default, 'ok' will be used\n" + "\n" + "'ncontext --create' exits with code 254 iff the context exists already.\n" + "\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "ncontext " VERSION " -- manages the creation of network contexts\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2004-2006 Enrico Scholz\n" + "Copyright (C) 2006 Daniel Hokka Zakrisson\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +#include "context-sync.hc" + +static inline ALWAYSINLINE void +tellContext(nid_t nid, bool do_it) +{ + char buf[sizeof(nid_t)*3+2]; + size_t l; + + if (!do_it) return; + + l = utilvserver_fmt_long(buf,nid); + + WRITE_MSG(1, "New network context is "); + Vwrite (1, buf, l); + WRITE_MSG(1, "\n"); +} + +static int +connectExternalSync(char const *filename) +{ + int fd; + struct sockaddr_un addr; + + if (filename==0) return -1; + + ENSC_INIT_UNIX_SOCK(addr, filename); + + fd = Esocket(PF_UNIX, SOCK_STREAM, 0); + Econnect(fd, &addr, sizeof(addr)); + + return fd; +} + +static void +doExternalSync(int fd, char const *msg) +{ + char c; + + if (fd==-1) return; + + if (msg) EsendAll(fd, msg, strlen(msg)); + Eshutdown(fd, SHUT_WR); + + if (TEMP_FAILURE_RETRY(recv(fd, &c, 1, MSG_NOSIGNAL))!=0) { + WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unexpected external synchronization event\n"); + exit(wrapper_exit_code); + } + + Eclose(fd); +} + +static inline ALWAYSINLINE int +doit(struct Arguments const *args, int argc, char *argv[]) +{ + int p[2][2]; + pid_t pid = initSync(p, args->do_disconnect); + + if (pid==0) { + nid_t nid; + int ext_sync_fd = connectExternalSync(args->sync_sock); + + doSyncStage0(p, args->do_disconnect); + + if (args->do_create) { + nid = vc_net_create(args->nid); + if (nid==VC_NOCTX) { + switch (errno) { + case EEXIST : + if (!args->is_silentexist) + perror(ENSC_WRAPPERS_PREFIX "vc_net_create()"); + return 254; + default : + perror(ENSC_WRAPPERS_PREFIX "vc_net_create()"); + return wrapper_exit_code; + } + } + tellContext(nid, args->verbosity>=1); + } + else + nid = args->nid; + + if (args->do_migrate && !args->do_migrateself) + Evc_net_migrate(nid); + + doExternalSync(ext_sync_fd, args->sync_msg); + doSyncStage1(p, args->do_disconnect); + DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid()); + execvp (argv[optind],argv+optind); + doSyncStage2(p, args->do_disconnect); + + PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]); + exit(wrapper_exit_code); + } + + assert(args->do_disconnect); + + waitOnSync(pid, p, args->nid!=VC_DYNAMIC_XID && args->do_migrate); + return EXIT_SUCCESS; +} + +int main (int argc, char *argv[]) +{ + struct Arguments args = { + .nid = VC_DYNAMIC_XID, + .do_create = false, + .do_migrate = false, + .do_migrateself = false, + .do_disconnect = false, + .is_silentexist = false, + .verbosity = 1, + .sync_msg = "ok", + }; + + while (1) { + int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0); + if (c==-1) break; + + switch (c) { + case CMD_HELP : showHelp(1, argv[0], 0); + case CMD_VERSION : showVersion(); + case CMD_CREATE : args.do_create = true; break; + case CMD_MIGRATE : args.do_migrate = true; break; + case CMD_DISCONNECT : args.do_disconnect = true; break; + case CMD_SILENTEXIST : args.is_silentexist = true; break; + case CMD_SYNCSOCK : args.sync_sock = optarg; break; + case CMD_SYNCMSG : args.sync_msg = optarg; break; + case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break; + case CMD_SILENT : --args.verbosity; break; + case CMD_MIGRATESELF : + args.do_migrate = true; + args.do_migrateself = true; + break; + + default : + WRITE_MSG(2, "Try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help' for more information.\n"); + return wrapper_exit_code; + break; + } + } + + signal(SIGCHLD, SIG_DFL); + + if (args.do_migrateself) + args.nid = Evc_get_task_nid(0); + + if (!args.do_create && !args.do_migrate) + WRITE_MSG(2, "Neither '--create' nor '--migrate specified; try '--help' for more information\n"); + else if (args.do_create && args.do_migrate) + WRITE_MSG(2, "Can not specify '--create' and '--migrate' at the same time; try '--help' for more information\n"); + else if (!args.do_create && args.nid==VC_DYNAMIC_XID) + WRITE_MSG(2, "Can not migrate to an unknown context\n"); + else if (optind>=argc) + WRITE_MSG(2, "No command given; use '--help' for more information.\n"); + else + return doit(&args, argc, argv); + + return wrapper_exit_code; +} -- 1.8.1.5