├── doc ├── proto.txt ├── Makefile.am ├── README ├── todo.txt └── uri.md ├── tests ├── parse │ ├── ipv4 │ ├── empty │ ├── singleopt │ ├── ipv6 │ ├── noopts │ ├── multiopt │ ├── Makefile.am │ └── parser.c ├── Makefile.am ├── code │ ├── .gitignore │ ├── punchdummy.c │ ├── macro.h │ ├── size.c │ ├── mask.c │ ├── Makefile.am │ ├── dup.c │ ├── trim.c │ └── clientacl.c └── run │ ├── certs │ ├── ca.info │ ├── server.info │ ├── client.info │ ├── ca-cert.pem │ ├── server-cert.pem │ ├── selfsigned-cert.pem │ ├── client-cert.pem │ ├── selfsigned-key.pem │ ├── ca-key.pem │ ├── client-key.pem │ ├── server-key.pem │ └── README.md │ ├── integrity-test.tr │ ├── integrityhuge-test.tr │ ├── cwrap_test │ ├── Makefile.am │ └── simple_test ├── systemd ├── .gitignore ├── sh.tmpl ├── Makefile.am ├── nbd@.service.tmpl └── nbd@.service.sh.in ├── .dir-locals.el ├── autogen.sh ├── backend.h ├── .mailmap ├── support └── genver.sh ├── coverity_model.c ├── nbd-debug.h ├── nbdtab_lexer.l ├── lfs.h ├── .github └── workflows │ └── build.yml ├── man ├── Makefile.am ├── nbd-trplay.1.sgml.in ├── nbd-trdump.1.sgml.in ├── nbdtab.5.sgml.in └── nbd-server.1.sgml.in ├── treefiles.h ├── netdb-compat.h ├── nbdtab_parser.y ├── nbdclt.h ├── .gitignore ├── maketr ├── CodingStyle ├── crypto-gnutls.h ├── buffer.h ├── nbd-helper.h ├── Makefile.am ├── make-integrityhuge.c ├── nbd-netlink.h ├── nbd-get-status.c ├── treefiles.c ├── cliserv.c ├── nbd.h ├── nbd-trdump.c ├── cliserv.h ├── buffer.c ├── README.md ├── nbd-trplay.c ├── nbdsrv.c ├── nbdsrv.h ├── configure.ac └── crypto-gnutls.c /doc/proto.txt: -------------------------------------------------------------------------------- 1 | proto.md -------------------------------------------------------------------------------- /tests/parse/ipv4: -------------------------------------------------------------------------------- 1 | nbd0 192.168.1.1 test 2 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = parse code run 2 | -------------------------------------------------------------------------------- /systemd/.gitignore: -------------------------------------------------------------------------------- 1 | nbd@.service 2 | nbd@.service.sh 3 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = README proto.md todo.txt uri.md 2 | -------------------------------------------------------------------------------- /tests/parse/empty: -------------------------------------------------------------------------------- 1 | # This file is empty, apart from the comments 2 | -------------------------------------------------------------------------------- /tests/code/.gitignore: -------------------------------------------------------------------------------- 1 | clientacl 2 | dup 3 | mask 4 | size 5 | trim 6 | -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((c-mode . ((c-file-style . "linux") 2 | (indent-tabs-mode . t)))) 3 | -------------------------------------------------------------------------------- /tests/run/certs/ca.info: -------------------------------------------------------------------------------- 1 | cn = Alex Bligh 2 | ca 3 | cert_signing_key 4 | expiration_days = 3650 5 | -------------------------------------------------------------------------------- /tests/run/integrity-test.tr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetworkBlockDevice/nbd/HEAD/tests/run/integrity-test.tr -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | make -C systemd -f Makefile.am nbd@.service.sh.in 4 | exec autoreconf -f -i 5 | -------------------------------------------------------------------------------- /tests/run/integrityhuge-test.tr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetworkBlockDevice/nbd/HEAD/tests/run/integrityhuge-test.tr -------------------------------------------------------------------------------- /tests/parse/singleopt: -------------------------------------------------------------------------------- 1 | # This config file has a valid configuration with a single option. 2 | nbd0 localhost test bs=1024 3 | -------------------------------------------------------------------------------- /backend.h: -------------------------------------------------------------------------------- 1 | #ifndef NBD_BACKEND_H 2 | #define NBD_BACKEND_H 3 | 4 | void punch_hole(int fd, off_t off, off_t len); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /systemd/sh.tmpl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | prefix=@prefix@ 4 | exec_prefix=@exec_prefix@ 5 | sysconfdir=@sysconfdir@ 6 | 7 | cat < 5 | -------------------------------------------------------------------------------- /tests/parse/noopts: -------------------------------------------------------------------------------- 1 | # This file contains a definition without options. It does not have 2 | # "/dev" in front of the device name, and has a multiline comment. 3 | nbd0 localhost test 4 | -------------------------------------------------------------------------------- /tests/code/punchdummy.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | void punch_hole(int fd, off_t off, off_t len) { 7 | g_assert_not_reached(); 8 | } 9 | -------------------------------------------------------------------------------- /support/genver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | GITDESC=$(git describe --dirty|sed -e 's/nbd-//' 2>/dev/null) 4 | 5 | if [ -z "$GITDESC" ]; then 6 | GITDESC="0.unknown" 7 | fi 8 | 9 | echo $GITDESC 10 | -------------------------------------------------------------------------------- /tests/parse/multiopt: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This config file contains a few empty lines. 4 | 5 | # It also contains multiple options on the configuration line. 6 | 7 | nbd0 localhost test bs=1024,no_optgo 8 | -------------------------------------------------------------------------------- /coverity_model.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct _GArray GArray; 3 | #define g_array_append_val(a, v) g_array_append_vals(a, &(v), 1) 4 | 5 | GArray* g_array_append_vals(GArray*, void*, unsigned int) { 6 | __coverity_escape__; 7 | } 8 | -------------------------------------------------------------------------------- /tests/run/certs/client.info: -------------------------------------------------------------------------------- 1 | country = GB 2 | state = London 3 | locality = London 4 | organization = Name of your organization 5 | cn = localhost 6 | tls_www_client 7 | encryption_key 8 | signing_key 9 | expiration_days = 3650 -------------------------------------------------------------------------------- /tests/code/macro.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_MACRO_H 2 | #define TEST_MACRO_H 3 | 4 | #include 5 | #include 6 | 7 | static int test_macro_counter = 0; 8 | #define count_assert(EXPR) { printf("%d\n", ++test_macro_counter); assert(EXPR); } 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /tests/run/cwrap_test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SOCKET_WRAPPER_DIR=$(mktemp -d) 4 | export LD_PRELOAD="libsocket_wrapper.so libnss_wrapper.so" 5 | 6 | cleanup_sw() { 7 | rm -rf $SOCKET_WRAPPER_DIR 8 | } 9 | 10 | trap -- cleanup_sw EXIT 11 | 12 | $(dirname $0)/simple_test "$@" 13 | 14 | exit $? 15 | -------------------------------------------------------------------------------- /nbd-debug.h: -------------------------------------------------------------------------------- 1 | #ifndef NBD_DEBUG_H 2 | #define NBD_DEBUG_H 3 | #include "config.h" 4 | /* Debugging macros */ 5 | #ifdef DODBG 6 | #define DEBUG(...) printf(__VA_ARGS__) 7 | #else 8 | #define DEBUG(...) 9 | #endif 10 | #ifndef PACKAGE_VERSION 11 | #define PACKAGE_VERSION "" 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /tests/parse/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir) 2 | check_PROGRAMS = parser 3 | TESTS_ENVIRONMENT = $(builddir)/parser 4 | parser_SOURCES = parser.c 5 | parser_LDADD = $(top_builddir)/libnbdclt.la $(top_builddir)/libcliserv.la 6 | TESTS = empty noopts singleopt multiopt ipv6 ipv4 7 | EXTRA_DIST=$(TESTS) 8 | -------------------------------------------------------------------------------- /nbdtab_lexer.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "nbdtab_parser.tab.h" 3 | %} 4 | 5 | %option noyywrap 6 | 7 | %% 8 | 9 | #[^\n]*\n { /* ignoring comments */ } 10 | [ \t]+ { yylval = strdup(yytext); return SPACE; } 11 | [^ \t\n,=]+ { yylval = strdup(yytext); return STRING; } 12 | . { yylval = strdup(yytext); return *yytext; } 13 | \n { yylval = strdup(yytext); return *yytext; } 14 | -------------------------------------------------------------------------------- /lfs.h: -------------------------------------------------------------------------------- 1 | #ifndef LFS_H 2 | #define LFS_H 3 | 4 | #include "config.h" 5 | #if NBD_LFS 6 | # define _FILE_OFFSET_BITS 64 7 | # ifndef _LARGEFILE_SOURCE 8 | # define _LARGEFILE_SOURCE 9 | # endif 10 | # define PARAM_OFFT PARAM_INT64 11 | #else 12 | # define PARAM_OFFT PARAM_INT 13 | #endif /* NBD_LFS */ 14 | #ifdef HAVE_SYNC_FILE_RANGE 15 | # define USE_SYNC_FILE_RANGE 16 | # define _GNU_SOURCE 17 | #endif /* HAVE_SYNC_FILE_RANGE */ 18 | 19 | #endif /* LFS_H */ 20 | -------------------------------------------------------------------------------- /systemd/Makefile.am: -------------------------------------------------------------------------------- 1 | #if SYSTEMD 2 | #systemdunitdir = $(DESTDIR)/$(SYSTEMDLOC) 3 | #systemdunit_DATA = nbd@.service 4 | #endif 5 | 6 | noinst_DATA = nbd@.service 7 | DISTCLEANFILES = nbd@.service 8 | EXTRA_DIST=nbd@.service.tmpl sh.tmpl 9 | 10 | nbd@.service: nbd@.service.sh 11 | sh nbd@.service.sh > nbd@.service 12 | 13 | nbd@.service.sh.in: nbd@.service.tmpl sh.tmpl 14 | cat sh.tmpl nbd@.service.tmpl > nbd@.service.sh.in 15 | echo EOF >> nbd@.service.sh.in 16 | -------------------------------------------------------------------------------- /tests/code/size.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "macro.h" 5 | 6 | int main(void) { 7 | char filename[] = "/tmp/nbd.XXXXXX"; 8 | int fd = mkstemp(filename); 9 | unlink(filename); 10 | 11 | count_assert(fd >= 0); 12 | count_assert(lseek(fd, 1023, SEEK_SET) == 1023); 13 | count_assert(write(fd, filename, 1) == 1); 14 | 15 | count_assert(size_autodetect(fd) == 1024); 16 | count_assert(size_autodetect(fd) != 1023); 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build NBD 2 | on: [push] 3 | jobs: 4 | Build-NBD: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: install dependencies 8 | run: sudo apt-get update && sudo apt-get -y install docbook-utils libglib2.0-dev libgnutls28-dev libnl-genl-3-dev autoconf-archive 9 | - name: Check out repository 10 | uses: actions/checkout@v4 11 | - run: ./autogen.sh 12 | - run: ./configure --enable-syslog 13 | - run: make distcheck 14 | -------------------------------------------------------------------------------- /tests/code/mask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) { 6 | count_assert(getmaskbyte(0) == 0); 7 | count_assert(getmaskbyte(1) == 0x80); 8 | count_assert(getmaskbyte(2) == 0xC0); 9 | count_assert(getmaskbyte(3) == 0xE0); 10 | count_assert(getmaskbyte(4) == 0xF0); 11 | count_assert(getmaskbyte(5) == 0xF8); 12 | count_assert(getmaskbyte(6) == 0xFC); 13 | count_assert(getmaskbyte(7) == 0xFE); 14 | count_assert(getmaskbyte(8) == 0xFF); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /man/Makefile.am: -------------------------------------------------------------------------------- 1 | CLEANFILES = manpage.links manpage.refs 2 | DISTCLEANFILES = nbd-server.1 nbd-server.1.sgml nbd-client.8 nbd-client.8.sgml nbd-server.5 nbd-server.5.sgml nbd-trdump.1 nbd-trdump.1.sgml nbd-trplay.1 nbd-trplay.1.sgml nbdtab.5 nbdtab.5.sgml 3 | EXTRA_DIST = nbd-server.1.sgml.in nbd-client.8.sgml.in nbd-server.5.sgml.in nbd-trdump.1.sgml.in nbd-trplay.1.sgml.in nbdtab.5.sgml.in 4 | 5 | if MANPAGES 6 | man_MANS = nbd-server.1 nbd-server.5 nbd-client.8 nbd-trdump.1 nbd-trplay.1 nbdtab.5 7 | %: %.sgml 8 | docbook2man $< 9 | endif 10 | -------------------------------------------------------------------------------- /treefiles.h: -------------------------------------------------------------------------------- 1 | #ifndef NBD_TREEFILES_H 2 | #define NBD_TREEFILES_H 3 | 4 | #include 5 | #include 6 | 7 | #define TREEDIRSIZE 1024 /**< number of files per subdirectory (or subdirs per subdirectory) */ 8 | #define TREEPAGESIZE 4096 /**< tree (block) files uses those chunks */ 9 | 10 | void construct_path(char *name, int lenmax, off_t size, off_t pos, off_t *ppos); 11 | void delete_treefile(char *name, off_t size, off_t pos); 12 | void mkdir_path(char *path); 13 | int open_treefile(char *name, mode_t mode, off_t size, off_t pos, pthread_mutex_t *mutex); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /netdb-compat.h: -------------------------------------------------------------------------------- 1 | #ifndef NETDB_COMPAT_H 2 | #define NETDB_COMPAT_H 3 | 4 | /* AI_NUMERICSERV as a value for the `ai_flags' member 5 | * of `struct addrinfo' of header has only 6 | * been available since: 7 | * 8 | * POSIX 1003.1-2008, Issue 7 9 | * glibc 2.3.4 10 | * Mac OS X 10.6 11 | * etc. 12 | * 13 | * Fortunately, its main purpose seems to be only 14 | * to optimize calls of `getaddrinfo', and because it 15 | * is meant to be a bit flag, it can therefore be 16 | * [relatively] safely ignored by defining it to have 17 | * the value zero. 18 | */ 19 | 20 | #ifndef AI_NUMERICSERV 21 | #define AI_NUMERICSERV 0 22 | #endif 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /nbdtab_parser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | extern int yylex(); 3 | #include 4 | #include 5 | #include 6 | #include "nbdclt.h" 7 | typedef char * YYSTYPE; 8 | %} 9 | 10 | %define parse.trace 11 | %define api.value.type {char *} 12 | 13 | %token SPACE 14 | %token STRING 15 | 16 | %% 17 | 18 | nbdtab: 19 | %empty 20 | | '\n' nbdtab 21 | | mountdef nbdtab 22 | ; 23 | 24 | mountdef: 25 | STRING SPACE STRING SPACE STRING optlist { nbdtab_commit_line($1, $3, $5); } 26 | ; 27 | 28 | optlist: 29 | %empty 30 | | SPACE options 31 | ; 32 | 33 | options: 34 | options ',' option 35 | | option 36 | ; 37 | 38 | option: 39 | STRING { nbdtab_set_flag($1); } 40 | | STRING '=' STRING { nbdtab_set_property($1, $3); } 41 | ; 42 | -------------------------------------------------------------------------------- /nbdclt.h: -------------------------------------------------------------------------------- 1 | #ifndef NBDCLT_H 2 | #define NBDCLT_H 3 | 4 | typedef struct { 5 | char *name; 6 | char *dev; 7 | char *hostn; 8 | char *port; 9 | char *cert; 10 | char *key; 11 | char *cacert; 12 | char *tlshostn; 13 | int bs; 14 | int timeout; 15 | int nconn; 16 | uint64_t force_size64; 17 | uint64_t size64; 18 | bool no_optgo; 19 | bool persist; 20 | bool swap; 21 | bool sdp; 22 | bool b_unix; 23 | bool preinit; 24 | bool force_ro; 25 | bool tls; 26 | char *priority; 27 | } CLIENT; 28 | 29 | extern void nbdtab_set_property(char *property, char *val); 30 | extern void nbdtab_set_flag(char *property); 31 | extern void nbdtab_commit_line(char *devn, char *hostn, char *exportname); 32 | extern void yyerror(char *msg); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /tests/code/Makefile.am: -------------------------------------------------------------------------------- 1 | TESTS = clientacl dup mask size trim 2 | check_PROGRAMS = clientacl dup mask size trim 3 | EXTRA_DIST = macro.h 4 | 5 | AM_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ 6 | AM_CPPFLAGS = -I$(top_srcdir) 7 | 8 | clientacl_SOURCES = clientacl.c punchdummy.c 9 | clientacl_LDADD = $(top_builddir)/libnbdsrv.la $(top_builddir)/libcliserv.la @GLIB_LIBS@ 10 | 11 | dup_SOURCES = dup.c punchdummy.c 12 | dup_LDADD = $(top_builddir)/libnbdsrv.la $(top_builddir)/libcliserv.la @GLIB_LIBS@ 13 | 14 | mask_SOURCES = mask.c punchdummy.c 15 | mask_LDADD = $(top_builddir)/libnbdsrv.la $(top_builddir)/libcliserv.la @GLIB_LIBS@ 16 | 17 | size_SOURCES = size.c punchdummy.c 18 | size_LDADD = $(top_builddir)/libnbdsrv.la $(top_builddir)/libcliserv.la @GLIB_LIBS@ 19 | 20 | trim_SOURCES = trim.c 21 | trim_LDADD = $(top_builddir)/libnbdsrv.la $(top_builddir)/libcliserv.la @GLIB_LIBS@ 22 | -------------------------------------------------------------------------------- /systemd/nbd@.service.tmpl: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=NBD client connection for %i 3 | Documentation=man:nbd-client 4 | PartOf=nbd.service 5 | Before=dev-%i.device 6 | Before=remote-fs-pre.target 7 | Requirs=modprobe@nbd.service 8 | After=network-online.target 9 | After=modprobe@nbd.service 10 | Conflicts=shutdown.target 11 | DefaultDependencies=no 12 | [Service] 13 | Type=forking 14 | ExecStart=@sbindir@/nbd-client %i 15 | [Install] 16 | RequiredBy=dev-%i.device 17 | RequiredBy=dev-%ip1.device 18 | RequiredBy=dev-%ip2.device 19 | RequiredBy=dev-%ip3.device 20 | RequiredBy=dev-%ip4.device 21 | RequiredBy=dev-%ip5.device 22 | RequiredBy=dev-%ip6.device 23 | RequiredBy=dev-%ip7.device 24 | RequiredBy=dev-%ip8.device 25 | RequiredBy=dev-%ip9.device 26 | RequiredBy=dev-%ip10.device 27 | RequiredBy=dev-%ip11.device 28 | RequiredBy=dev-%ip12.device 29 | RequiredBy=dev-%ip13.device 30 | RequiredBy=dev-%ip14.device 31 | RequiredBy=dev-%ip15.device 32 | -------------------------------------------------------------------------------- /systemd/nbd@.service.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | prefix=@prefix@ 4 | exec_prefix=@exec_prefix@ 5 | sysconfdir=@sysconfdir@ 6 | 7 | cat <${conffile} <&1 >/dev/null 32 | umount /mnt 33 | mount -t ext3 -odata=journal,barrier=1 /dev/nbd0 /mnt 34 | (cd /mnt ; tar cvzf /dev/null . ; sync) 2>&1 >/dev/null 35 | dbench -D /mnt 1 & 36 | sleep 10 37 | killall dbench 38 | sleep 2 39 | killall -KILL dbench 40 | sync 41 | umount /mnt 42 | ./nbd-client -d /dev/nbd0 43 | if [ -f ${pidfile} ] 44 | then 45 | kill `cat ${pidfile}` 46 | rm -f ${pidfile} 47 | else 48 | kill $PID 49 | fi 50 | rm -f $tmpnam ${conffile} 51 | ls -la ${output} 52 | -------------------------------------------------------------------------------- /tests/run/certs/server-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDsDCCAmigAwIBAgIUWxSn6kYFMM05Wk3oJphIxLgb094wDQYJKoZIhvcNAQEL 3 | BQAwFTETMBEGA1UEAxMKQWxleCBCbGlnaDAeFw0yMzA2MjIwODU1MDBaFw0zMzA2 4 | MTkwODU1MDBaMDgxIjAgBgNVBAoTGU5hbWUgb2YgeW91ciBvcmdhbml6YXRpb24x 5 | EjAQBgNVBAMTCWxvY2FsaG9zdDCCAVIwDQYJKoZIhvcNAQEBBQADggE/ADCCAToC 6 | ggExANfdKiPCHLeeY3raNxLpiMbm9svwHvQls+RAIVFkBVUHNSFsSJdPENjdnBcv 7 | PZGoGdg4g7EnJukGbpohPz8j+8uaV5Ujp/w2fqfyvovSzc5xh7hGUKmCyF8IbCPs 8 | RDGvij+uTYDP7wJ6Z+WXWiQkiUdqRi9SGo7M4sfp9+zPIzDLxKKaNFo4/ho5yJJv 9 | zzyyHzl560fqQaxPJ6eKeyb3CZ1t6hbfs8uxiKN3/fcI5GjIxJdBLneQ6RfZ9FXE 10 | SLUXzQkSy00+yDn3JejPv3Vhmv6SLinYaaDZsGcc3RnPYUA5a/kC06VvDNcc8dDH 11 | 6tKySDn0qUkl8NNO4sAKg2FXfA9wIus5lWOQo0cqc8p4IgGHNNkGR6PNFNeSaAu9 12 | ZYIeUUxUqKVwwpYASdIKzATV77cCAwEAAaN1MHMwDAYDVR0TAQH/BAIwADATBgNV 13 | HSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0OBBYEFD6D8W6F 14 | Rm4xyy15aaCH4AvBycUPMB8GA1UdIwQYMBaAFGCjGs4nzrJXYOSvbznm6punEXkO 15 | MA0GCSqGSIb3DQEBCwUAA4IBMQAhfI3SSVN1+OFyHSN2XpALHSC84wcPwifwPCsG 16 | +sq6DR+4Q1VhbVkot+qVBQkjne4zCpPKwXMkehteKhRICA/lcr4/A7MyVUu3pYWz 17 | T5kCCe70jdh7FGw47jz32TLuFPRNBzPTkMXAYpzfX8zr+i8G1Tiwi2YD6hchTdMW 18 | bvRZannPUQCaaRDzLwnIURgMNFIIG+7KbfdOCyClb3drG2pE4RP9z0kZWXdIG5bg 19 | 2F+G9Q8Syao0oMrEQWwOnHLF/aIa3R2rIg56u/EDD1Lrp/7vTVAhoG+OgnuRWw0R 20 | 0CRUN134xfNg/afhlW/5eueF9mZdKu5RdkDqjn2yIUAIbsCHa0lGOwEWM8vcCrt5 21 | dER1BLvrylEuM6ivYLBMOGzRNA/HAqcXw16mtpcElycLyg+g 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/run/certs/selfsigned-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDvDCCAqSgAwIBAgIJANew2ax/i9zaMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNV 3 | BAYTAkJFMRAwDgYDVQQIDAdBbnR3ZXJwMREwDwYDVQQHDAhNZWNoZWxlbjEdMBsG 4 | A1UECgwUTmV0d29yayBCbG9jayBEZXZpY2UxIDAeBgNVBAMMF25iZC5zZWxmLXNp 5 | Z25lZC5pbnZhbGlkMB4XDTE2MTIxOTE3MzM0MVoXDTI2MTIxNzE3MzM0MVowczEL 6 | MAkGA1UEBhMCQkUxEDAOBgNVBAgMB0FudHdlcnAxETAPBgNVBAcMCE1lY2hlbGVu 7 | MR0wGwYDVQQKDBROZXR3b3JrIEJsb2NrIERldmljZTEgMB4GA1UEAwwXbmJkLnNl 8 | bGYtc2lnbmVkLmludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB 9 | AQCo5u44umcplqnE9chyyVTw/Q9EBnecT7PQ5tbX99NlMD+u4Gy9mvwD+BG8B9M5 10 | BhrmBBAh3xsC31NBNbMGkMzMUE8d3+C/5IWfqB/t/0oZcxf9fTPBJjUGQNqGUc5l 11 | AjAXw2pIQLLId27wNKOpmaSiaZCVmVKGBaMLEqddFnS/npPUiMQMdH+PwbFreQpg 12 | td4vA4PuoLKCQwbr2UBjgwnYdZbpr9YevyGZldp7OvmAqOoR7wUZJrPV54UFG3z/ 13 | Awa3H2bYsgOX+lk8Ih27kNs7tobeqr1r3wrBgv6O3lUyVQAy88insxSYZwp+KSeP 14 | 12d95vC0Z8V/GQKbXeN04z2HAgMBAAGjUzBRMB0GA1UdDgQWBBQvz4Uon2bKjPvm 15 | 339jNbtcLNvchTAfBgNVHSMEGDAWgBQvz4Uon2bKjPvm339jNbtcLNvchTAPBgNV 16 | HRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBjf/que01iAJh7UAYP3uPf 17 | snNqQj8IJwV+HtUlWkNAore9DzgGWAlwxksZG5dcOwoGeURnulQ6BnjegwLbkDhY 18 | xihorIMoPGW4g+9fvEHhKezi45yDEORw6nbZSKAq9Du9lHUMByn+PthHz63G2Nxc 19 | bbqHNt2iPsVH1qWp1TRe1A4SHS5gDBO8+5B5nII6Jw+fHB84WJMx4dsjtQqX4FMr 20 | 7YmA+kyARsyt6h1rXdZLYXZKT60wWhEhZOgXvxFI3RNCy4yBurTJvwzEcMrnLrbh 21 | H5wEc9HXwwyTDJlnSUBEtBErZve6b8ZWDefuGi2TAxqN9OJDE3pp6UzC4odV2TPs 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/run/certs/client-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID3zCCApegAwIBAgIUWpyk3l+KkBJ/RyoXNbno/oY3a6AwDQYJKoZIhvcNAQEL 3 | BQAwFTETMBEGA1UEAxMKQWxleCBCbGlnaDAeFw0yMzA2MjIwODU1MzFaFw0zMzA2 4 | MTkwODU1MzFaMGcxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNV 5 | BAcTBkxvbmRvbjEiMCAGA1UEChMZTmFtZSBvZiB5b3VyIG9yZ2FuaXphdGlvbjES 6 | MBAGA1UEAxMJbG9jYWxob3N0MIIBUjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKC 7 | ATEAv/0IYsxRwCYX3xjF3JF4PMibdgI+GxjFRm1LghgkKkI8DEN5WiiyskAT3AGI 8 | lK0Hp5LoXc5UZjKEIiAxP1BikL4K6UEvm3Nv6JubUB0ScWdkREp7vsw5rm3bJr51 9 | lgGm5HwWwV5/aavkWbzDDPHKZw8jL7/XUG/Zlj7ZyUmgqGSCni+lQQRbVMYViM9U 10 | hjfxpMcp7A1nqWSd2GLX7TD+XHbnnGDwTWy+eNwuzI7oRiio6hzwolcWW39x4VnW 11 | UuVnjMrZTze5i3WjYFw/0C+N3KRVEIZr/w3YhliMOiM98VAa5SOL638pWzRnQjtS 12 | ulQwTc/ySBjaRMVHMl6JPsMSfwx4yGJJz5QiLRzfbMpvoBeFFk6kcOxaxFF/t6d/ 13 | JWc+QnGYnUWJolvZSIGWfXf8TQIDAQABo3UwczAMBgNVHRMBAf8EAjAAMBMGA1Ud 14 | JQQMMAoGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIFoDAdBgNVHQ4EFgQU1N4ony/3 15 | Uv4Q6OaNGne5Qmb57SEwHwYDVR0jBBgwFoAUYKMazifOsldg5K9vOebqm6cReQ4w 16 | DQYJKoZIhvcNAQELBQADggExAH3E7wMt6Cg7Sr8evYDwQkI84hsKqzpK9cuFRUAE 17 | /FctEBXAdIpVVE72+TlpjBIC01WsI4fxU86hl8Er0W8wpyiNI4FksirbNFVk6e7r 18 | jKJGMSOfdY6kpqjJ8nOP727PWi3A/ZOEtij9GYQlD0DHxAMl+k+ekCmwS1KseD1c 19 | ri7NWoxK95NXEZEg5K1CxMqjQoVnSgQyhQP0XYKfB9ExnINVmP3IAQL0nKeRuU0h 20 | qiKWaLHNwej1HjsEEJnmpkRrAnkkvxXImBF1qaNl3NBlqcknikFIp21/l5lB4wMu 21 | MrJUI4t1tu2/2Sovw8nAwTMOfgG6c28bxd6pq/cNiHSkpFpQ+U4nVAau86uRrRD9 22 | zg+uvo8n8Pki/bwg/if+cdmVspSe9Lyf2tUtCm/XoPZQWcI= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /tests/run/Makefile.am: -------------------------------------------------------------------------------- 1 | if GNUTLS 2 | TLSSRC = $(top_srcdir)/crypto-gnutls.c $(top_srcdir)/crypto-gnutls.h $(top_srcdir)/buffer.c $(top_srcdir)/buffer.h 3 | else 4 | TLSSRC = 5 | endif 6 | #if CWRAP 7 | #TESTS_ENVIRONMENT=$(srcdir)/cwrap_test 8 | #else 9 | TESTS_ENVIRONMENT=$(srcdir)/simple_test 10 | #endif 11 | TESTS = cfg1 cfgmulti cfgnew cfgsize write flush integrity dirconfig list inetd \ 12 | rowrite tree rotree unix integrityhuge handshake tls tlswrongcert tlshuge 13 | XFAIL_TESTS=@RUN_XFAIL@ 14 | check_PROGRAMS = nbd-tester-client 15 | nbd_tester_client_SOURCES = nbd-tester-client.c 16 | nodist_nbd_tester_client_SOURCES = cliserv.c 17 | nbd_tester_client_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ 18 | nbd_tester_client_CPPFLAGS = -I$(top_srcdir) 19 | nbd_tester_client_LDADD = @GLIB_LIBS@ 20 | if GNUTLS 21 | nodist_nbd_tester_client_SOURCES += buffer.c crypto-gnutls.c 22 | nbd_tester_client_CFLAGS += @GnuTLS_CFLAGS@ 23 | nbd_tester_client_LDADD += @GnuTLS_LIBS@ 24 | endif 25 | CLEANFILES = buffer.c crypto-gnutls.c cliserv.c 26 | EXTRA_DIST = integrity-test.tr integrityhuge-test.tr simple_test cwrap_test certs/client-key.pem certs/client-cert.pem certs/server-cert.pem certs/ca-cert.pem certs/ca.info certs/client.info certs/server-key.pem certs/ca-key.pem certs/server.info certs/README.md certs/selfsigned-cert.pem certs/selfsigned-key.pem 27 | cfg1: 28 | cfgmulti: 29 | cfgnew: 30 | cfgsize: 31 | write: 32 | flush: 33 | integrity: 34 | integrityhuge: 35 | dirconfig: 36 | list: 37 | rowrite: 38 | tree: 39 | rotree: 40 | unix: 41 | inetd: 42 | handshake: 43 | tls: 44 | tlshuge: 45 | tlswrongcert: 46 | -------------------------------------------------------------------------------- /tests/code/dup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "macro.h" 5 | 6 | int stringcmp(const char* a, const char* b) { 7 | if(a == NULL && b == NULL) { 8 | return 0; 9 | } 10 | if(a == NULL) { 11 | return 1; 12 | } 13 | if(b == NULL) { 14 | return -1; 15 | } 16 | return strcmp(a, b); 17 | } 18 | 19 | int main(void) { 20 | SERVER *srvd; 21 | SERVER srvs = { 22 | .exportname = "foo", 23 | .expected_size = 0, 24 | .listenaddr = "0.0.0.0", 25 | .authname = "/etc/foo", 26 | .flags = 0, 27 | .virtstyle = VIRT_CIDR, 28 | .cidrlen = 16, 29 | .prerun = NULL, 30 | .postrun = "/bin/bash", 31 | .servename = "test", 32 | .max_connections = 0, 33 | .transactionlog = "/etc/foo", 34 | .cowdir = "/tmp", 35 | }; 36 | 37 | srvd = dup_serve(&srvs); 38 | 39 | count_assert(&srvs != srvd); 40 | count_assert(stringcmp(srvs.exportname, srvd->exportname) == 0); 41 | count_assert(srvs.expected_size == srvd->expected_size); 42 | count_assert(stringcmp(srvs.listenaddr, srvd->listenaddr) == 0); 43 | count_assert(stringcmp(srvs.authname, srvd->authname) == 0); 44 | count_assert(srvs.flags == srvd->flags); 45 | count_assert(srvs.virtstyle == srvd->virtstyle); 46 | count_assert(srvs.cidrlen == srvd->cidrlen); 47 | count_assert(stringcmp(srvs.prerun, srvd->prerun) == 0); 48 | count_assert(stringcmp(srvs.postrun, srvs.postrun) == 0); 49 | count_assert(stringcmp(srvs.servename, srvd->servename) == 0); 50 | count_assert(srvs.max_connections == srvd->max_connections); 51 | count_assert(stringcmp(srvs.transactionlog, srvd->transactionlog) == 0); 52 | count_assert(stringcmp(srvs.cowdir, srvd->cowdir) == 0); 53 | } 54 | -------------------------------------------------------------------------------- /tests/code/trim.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include "macro.h" 10 | #include "backend.h" 11 | 12 | int g_fd; 13 | int g_off; 14 | int g_len; 15 | 16 | void punch_hole(int fd, off_t off, off_t len) { 17 | g_fd = fd; 18 | g_off = off; 19 | g_len = len; 20 | } 21 | 22 | int main(void) { 23 | struct nbd_request req; 24 | SERVER srv; 25 | CLIENT cl; 26 | FILE_INFO export; 27 | int spair[2]; 28 | 29 | req.magic = NBD_REQUEST_MAGIC; 30 | req.type = NBD_CMD_TRIM; 31 | req.from = 0; 32 | req.len = 1024*1024; 33 | 34 | srv.exportname = "dummy"; 35 | srv.expected_size = 1024*1024*1024; 36 | srv.listenaddr = "0.0.0.0"; 37 | srv.authname = NULL; 38 | srv.flags = 0; 39 | srv.virtstyle = VIRT_NONE; 40 | srv.cidrlen = 0; 41 | srv.prerun = NULL; 42 | srv.postrun = NULL; 43 | srv.servename = "dummy"; 44 | srv.transactionlog = NULL; 45 | srv.cowdir = NULL; 46 | 47 | export.fhandle = 123; 48 | export.startoff = 0; 49 | 50 | cl.exportsize = 1024*1024*1024; 51 | cl.clientname = "127.0.0.1"; 52 | cl.exportname = "dummy"; 53 | cl.export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO)); 54 | g_array_append_val(cl.export, export); 55 | socketpair(AF_UNIX, SOCK_STREAM, AF_UNIX, spair); 56 | cl.net = spair[0]; 57 | cl.server = &srv; 58 | cl.difffilename = NULL; 59 | cl.difffile = 0; 60 | cl.difffilelen = 0; 61 | cl.difmap = NULL; 62 | cl.transactionlogfd = -1; 63 | cl.clientfeats = 0; 64 | pthread_mutex_init(&cl.lock, NULL); 65 | 66 | /* phew. Now test: */ 67 | 68 | exptrim(&req, &cl); 69 | count_assert(g_fd == 123); 70 | count_assert(g_off == 0); 71 | count_assert(g_len == 1024*1024); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /CodingStyle: -------------------------------------------------------------------------------- 1 | NBD Coding style. 2 | ================= 3 | 4 | The following expresses my opinion of what C code should look like. I'm 5 | not as strict as the Kernel maintainers on this one (NBD isn't even 6 | remotely as large anyway), but code that does not follow these rules 7 | needs to be updated so that it does, which is useless time wasted for 8 | me. Therefore, it's appreciated if you would follow these rules. 9 | 10 | Thanks. 11 | 12 | * Use a tab width of 8 characters. You may use tab or 8 spaces as you 13 | please, it doesn't really matter to me. 14 | * opening curly brackets occur on the same line as whatever they're 15 | curly brackets for, _in all cases_. This includes function 16 | definitions, if structures, loops, and so on; every code block appears 17 | like so: 18 | 19 | int foo(int bar) { 20 | ... 21 | } 22 | 23 | * Variable declarations are separated from the rest of a function block 24 | by a line of whitespace. It's okay to assign a value to a variable 25 | when you're declaring it if you can do that on one line of code, but 26 | it must still be in the block of declarations at the top with a 27 | whiteline below. 28 | * Variables are declared one on each line. So no 29 | 30 | int foo, bar; 31 | 32 | use 33 | 34 | int foo; 35 | int bar; 36 | 37 | instead. 38 | * Try to fit everything in 80 columns. This goes especially for comment 39 | lines, but may be relaxed for function calls with 79 arguments, or so, 40 | if that's not feasible. 41 | * If your function block is more than three or so screenfulls, there's a 42 | hint that you should break it up. 43 | 44 | It is true that not all of the code currently follows these rules; but 45 | that should not stop you from following them for new code, or from 46 | cleaning up if you can (i.e., you have commit rights). 47 | -------------------------------------------------------------------------------- /tests/run/certs/selfsigned-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCo5u44umcplqnE 3 | 9chyyVTw/Q9EBnecT7PQ5tbX99NlMD+u4Gy9mvwD+BG8B9M5BhrmBBAh3xsC31NB 4 | NbMGkMzMUE8d3+C/5IWfqB/t/0oZcxf9fTPBJjUGQNqGUc5lAjAXw2pIQLLId27w 5 | NKOpmaSiaZCVmVKGBaMLEqddFnS/npPUiMQMdH+PwbFreQpgtd4vA4PuoLKCQwbr 6 | 2UBjgwnYdZbpr9YevyGZldp7OvmAqOoR7wUZJrPV54UFG3z/Awa3H2bYsgOX+lk8 7 | Ih27kNs7tobeqr1r3wrBgv6O3lUyVQAy88insxSYZwp+KSeP12d95vC0Z8V/GQKb 8 | XeN04z2HAgMBAAECggEAey4QRqcLXbVXkyF9UtmqbSbh30aoLQOjrJLt1QwUzBNo 9 | Hm3mYFGLwolExdEfJtNhAqer7Ef+NxYQbdpv+jXYZpmbWbpQ+yH6ofnHb5djvzPF 10 | J0YMXK00tp7NwHAhCmGSGYKXHKKywKj56404XxSCkUBUBgaPvNaXlhfAn48lDim1 11 | amKeAQW8q3egh78/6UWjPDTq44SVKJv5ujm4EYrTlMzagIHEA4rqpVGcDL0Micz0 12 | 4SIJy1lMnoj5IEiJZCrpPpYatQki/I8KGB6fIDN3BtNnhWcoOudok9+jqieZCfJv 13 | IlVoI5PZo1aO9hdRtRz1ZzAlC1mUoAK+umPZcLnZ4QKBgQDSmaDOdZYgyOtiAF1V 14 | jlHK1LQaHi1ZjpU7gaISCcBjjVitOptRbfTKt3fWtZ6G9Q5VrrxEvgZ26KVcZ0iJ 15 | a1sDrUpfK4XpXTZNZ8O0MZrRwImTljDcBTnJMo6lPOX7yB+LlcOan6peuFnxr1FY 16 | emyrQ/WvNb/Axi1xKXaYFPaGrQKBgQDNUB22Bm1DBpK3X3Rcvk7XYEPvSS4JNDP8 17 | A9pQwxwnl3IZlOBuzy0HohmNFvQhcFKUT+EWXhDge0AwfnMncQLt7WfNMUagL+oJ 18 | 8t+QAIJ/3CwUre16S7eOJ4mt6l2gba6wugtAmd6w0snVXEvHu5d0tgCzmo7owUdx 19 | Ut3/Ra7/gwKBgA8ZmtES10fUgCQPuKF4yd6ML7mrrj68nXCd09wNPPEmYlRRXm+R 20 | PbsHOp13ej1c9sEn/THEmjwOZETi1u2bd/Qkia+XNEvONiWIqhySbfJaJsMhQrGT 21 | 4lfNuzKX0jmiWLiubU754cJW34QXuPJqHL6O6d+9L9mHnByAB5PR9PclAoGAeDYE 22 | b2Nr7eaXWM6G7xZuSySOIjiSv8jU9yW6WbcjcPr3T4sfrUGYd/OtSjK6VinR8Ayl 23 | GdeRwh3oA3zGJ72/nVd3g2jqlTf4rEKMK2BhCEP9e04q0YQrwQvdTPsAPsJ5mfgU 24 | RorRHG8OxeH4bMWldCxsVLyWGCmyjuOaH7DJOckCgYAG8VnxbKz2X1arPsKyWnN4 25 | T/GkqfxskPP/jsE1N5iCHd0oKX7VigYBfFaTORcbTbP/T2SD0riHOaKqLQaq74qd 26 | vKTzvY0pQwdmxQiCvHMZ/jlBvIU+B6PxypdBGY8bfa1OyaIiE7eQGgNOxPeCSczJ 27 | XZwZCy04VYkH4mrlSDrt8Q== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /crypto-gnutls.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 Wrymouth Innovation Ltd 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | #ifndef __TLSPROXY_CRYPTO_GNUTLS_H 28 | #define __TLSPROXY_CRYPTO_GNUTLS_H 29 | 30 | int tlssession_init (); 31 | 32 | typedef struct tlssession tlssession_t; 33 | tlssession_t *tlssession_new (int isserver, 34 | char *keyfile, char *certfile, char *cacertfile, 35 | char *hostname, char *priority, int insecure, int debug, 36 | int (*quitfn) (void *opaque), 37 | int (*erroutfn) (void *opaque, 38 | const char *format, 39 | va_list ap), void *opaque); 40 | void tlssession_close (tlssession_t * s); 41 | int tlssession_mainloop (int cryptfd, int plainfd, tlssession_t * session); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Wrymouth Innovation Ltd 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in 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 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #ifndef __TLSPROXY_BUFFERS_H 26 | #define __TLSPROXY_BUFFERS_H 27 | 28 | #include 29 | #include 30 | 31 | typedef struct buffer buffer_t; 32 | 33 | buffer_t *bufNew (ssize_t size, ssize_t hwm); 34 | void bufFree (buffer_t * b); 35 | ssize_t bufGetReadSpan (buffer_t * b, void **addr); 36 | ssize_t bufGetWriteSpan (buffer_t * b, void **addr); 37 | void bufDoneRead (buffer_t * b, ssize_t size); 38 | void bufDoneWrite (buffer_t * b, ssize_t size); 39 | int bufIsEmpty (buffer_t * b); 40 | int bufIsFull (buffer_t * b); 41 | int bufIsOverHWM (buffer_t * b); 42 | ssize_t bufGetFree (buffer_t * b); 43 | ssize_t bufGetCount (buffer_t * b); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /tests/code/clientacl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | bool do_test(char* address, char* netmask) { 14 | struct addrinfo hints; 15 | struct addrinfo *res, *tmp; 16 | char buf[1024]; 17 | int err; 18 | 19 | printf("Doing test for %s, netmask %s\n", address, netmask); 20 | memset(&hints, 0, sizeof(hints)); 21 | hints.ai_family = AF_UNSPEC; 22 | hints.ai_flags = AI_NUMERICHOST; 23 | 24 | if((err = getaddrinfo(address, NULL, &hints, &res))) { 25 | fprintf(stderr, "E: %s\n", gai_strerror(err)); 26 | exit(EXIT_FAILURE); 27 | } 28 | tmp = res; 29 | while(res) { 30 | if((err = getnameinfo((struct sockaddr*)res->ai_addr, res->ai_addrlen, buf, 31 | sizeof (buf), NULL, 0, NI_NUMERICHOST))) { 32 | fprintf(stderr, "E: %s\n", gai_strerror(err)); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | printf("Found %s\n", buf); 37 | 38 | if(address_matches(netmask, (struct sockaddr*)res->ai_addr, NULL)) { 39 | printf("Yes!\n"); 40 | freeaddrinfo(tmp); 41 | return true; 42 | } else { 43 | printf("oh noes!\n"); 44 | } 45 | res = res->ai_next; 46 | } 47 | freeaddrinfo(tmp); 48 | return false; 49 | } 50 | 51 | int main(void) { 52 | if(!do_test("192.168.0.1", "192.168.1.1/23")) { 53 | return 1; 54 | } 55 | if(!do_test("192.168.0.1", "192.168.0.1/24")) { 56 | return 1; 57 | } 58 | if(!do_test("::ffff:192.168.200.1", "192.168.200.1/24")) { 59 | return 1; 60 | } 61 | if(do_test("::ffff:192.168.200.1", "192.168.100.1/24")) { 62 | return 1; 63 | } 64 | if(do_test("192.168.200.1", "192.168.0.0/24")) { 65 | return 1; 66 | } 67 | if(do_test("192.168.200.1", "192.168.0.0/23")) { 68 | return 1; 69 | } 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /nbd-helper.h: -------------------------------------------------------------------------------- 1 | #ifndef NBD_HELPER_H 2 | #define NBD_HELPER_H 3 | 4 | #include "nbd.h" 5 | 6 | /* Constants and macros */ 7 | 8 | /* 9 | * Constants for nbd_request.magic == NBD_TRACELOG_MAGIC 10 | */ 11 | /* 1) stored in nbd_req.type */ 12 | enum { 13 | /* enable/disable logging actual data. 14 | * nbd_request.len is the new value (true/false) 15 | */ 16 | NBD_TRACELOG_SET_DATALOG = 1 17 | }; 18 | 19 | /* 2) Must be in nbd_req.from */ 20 | #define NBD_TRACELOG_FROM_MAGIC 0x4A93BA39A54F31B6ULL 21 | 22 | /* Functions */ 23 | 24 | /** 25 | * Translate a command name into human readable form 26 | * 27 | * @param command The command number (after applying NBD_CMD_MASK_COMMAND) 28 | * @return pointer to the command name 29 | **/ 30 | #define ENUM2STR(x) case x: return #x 31 | static inline const char * getcommandname(uint32_t command) { 32 | switch (command) { 33 | ENUM2STR(NBD_CMD_READ); 34 | ENUM2STR(NBD_CMD_WRITE); 35 | ENUM2STR(NBD_CMD_DISC); 36 | ENUM2STR(NBD_CMD_FLUSH); 37 | ENUM2STR(NBD_CMD_TRIM); 38 | ENUM2STR(NBD_CMD_CACHE); 39 | ENUM2STR(NBD_CMD_WRITE_ZEROES); 40 | ENUM2STR(NBD_CMD_BLOCK_STATUS); 41 | ENUM2STR(NBD_CMD_RESIZE); 42 | default: 43 | return "UNKNOWN"; 44 | } 45 | } 46 | 47 | /** 48 | * Translate a tracelog parameter name into human readable form 49 | * 50 | * @type tracelog parameter number from struct nbd_req.type 51 | * @return pointer to the name 52 | **/ 53 | static inline const char * gettracelogname(uint32_t type) { 54 | switch (type) { 55 | ENUM2STR(NBD_TRACELOG_SET_DATALOG); 56 | default: 57 | return "UNKNOWN"; 58 | } 59 | } 60 | 61 | static inline const char *getstructreplname(uint16_t type) { 62 | switch(type) { 63 | ENUM2STR(NBD_REPLY_TYPE_NONE); 64 | ENUM2STR(NBD_REPLY_TYPE_OFFSET_DATA); 65 | ENUM2STR(NBD_REPLY_TYPE_OFFSET_HOLE); 66 | ENUM2STR(NBD_REPLY_TYPE_BLOCK_STATUS); 67 | 68 | ENUM2STR(NBD_REPLY_TYPE_ERROR); 69 | ENUM2STR(NBD_REPLY_TYPE_ERROR_OFFSET); 70 | default: 71 | return "UNKNOWN"; 72 | } 73 | } 74 | 75 | #undef ENUM2STR 76 | 77 | #endif //NBD_HELPER_H 78 | -------------------------------------------------------------------------------- /tests/run/certs/ca-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIFfAIBAAKCATEA2ym+Z6gee5dphCWupoBe23VIuReqPgcsQ+PyA1zUCqPnCdCt 3 | MVnCKo/N3uVkj4u43+lZn7S8WJmuMYngm3MgUkxHVd7uIXDRgUPPGdBf0FbIDYbk 4 | t0pri3IvV4gQrSsUAUq3MOf63c0colANFLM6u7PI3ESqsY/wCa/kLCBqShvkPD4Y 5 | wwkzrS6eSssb49c2/z5dxd2AXbw89R17BK4hcD7JG6xqSP05z1dqUsxzcG/H4Y16 6 | WNrCpCatCaEZkQ1wJTmAxIX3XVJpqGpF0hML5fLqm5JXe/2ibapW4B7MfsEF3dkc 7 | y0pkWkD7731x2Un2nOHII9qCyrPYpZrKuWpxQftOT/K7h06zu8VvOz7x+tG8J+tp 8 | 7fn9DaBY8N+H4jc8sNny99C+hMEB1Wc7gKqAGQIDAQABAoIBMAJSDpSj5HtmsW9n 9 | WRJPv9FfNvTTbJIeutKsM52NVScYsFimV5Mdx28dGdmvQEbp0ecNs40mmYDu/aJu 10 | JTfteo03MWErd1uDdDXEF/RcGbZHw54AYeRpRWVoVoUnfmpgT07/3Bvd35uLcVnB 11 | nbssoPr9pBXlpJC1PLN+49xYv9oG3L42N8Zm5Epu44OuDglLTScw4UbNTy+O3+qQ 12 | q+P++j2Ysnt53a20J5XgdBpAksjydFOkN8OdZIdeAGXeHA0svwUdw8Z3BJzv/cB/ 13 | KGI5BPTQh42BMGboog8k8uFUCA6P0ZkwAy4Cgf1801DRC+pBvBqeN3gBTRIpA6Rq 14 | p6RZTiTGTQF3gDbHHA7TJSIav+mv9aNZUFKtvu4QGqoT5qNz531gkdFi7eBwbA8V 15 | QjOnuAECgZkA65MCrjo4M2XzrVqKH2X8L6xd8eLYKlZEQrBJjZI6Ly0SK9wG5IRa 16 | bum62w8zJWZvk+a1985auXKA8gPeEbrpULNJv/OkSstqZhKFI+ckoJFmGu+cYqNv 17 | Al3/NeOYPeLW7v767XJhAdEfuBK3Ra7w+6qphRiLIbgK8MQuGxfYmgdu1hffjdOS 18 | WwNy2jyQby6p93nnKu7RxAECgZkA7ip1I+rSEpj3LkJvXt/9xC8SsAmjDEDpGxer 19 | oFkffj+jfIXNZN+kg6pvSO6stzvtjlgiWT/MLX9JYJW1eaTIVWBbmZ6D5R70jiUu 20 | RLI2bX1bFv50S9EN0wE/0IwoK7XfoScdRpJ4RJX8SV/Q7esPyKGHKbaHaeifYmkD 21 | rXehdE+gcQqoN4lTN7dnNYYBODwvosf3+1O+XBkCgZkAuZxCb25126GHxt3gmG6t 22 | rg5ckvqOIYWJERZ/TamaaJNVjvM1BxZ1fpBwZqtqPByi62DLnW2ctCNRD98WONgR 23 | f0FUaYaZu0jdE4GiH7C+fjkxvyVuDZYCIFZZgGdMC+7QNMz4fuAxKNJR8KHmf2Qg 24 | gdps6O52qWGuVRftz/EQ/APBQ7TZspCx7z4fX256yu90ggYtqvkylAECgZkA0YHx 25 | 5/WidI+xKTVx6SDbiB/srYTctGPJa3bIGFcuGA39UAYYJ3uAqf5cxOiIcOu7zrMD 26 | DEXN49wL/XXU3TwyqsAH9Dv4RK6VbRGSAQZQUMKsRa7zONqe8ZYwv9D7aXAlWAsj 27 | erhQKe1SsG0kSpa0HMbTMsOJnYXv507/2DHbioidV7OLRMd9uA6TMQc/vWtccDK+ 28 | l40UcMkCgZgNteR/raLb/9BV3p6MOVlueT9nJNbxLN46qA74SVzLDQ4HKDJvI1iR 29 | 0sE3Vx3FZXxPebzEiSHbM1XvUamriG+PvSJ3E0Nd6RGrD6jfFNnqozXOOd9kcIQD 30 | IYtyv1mFKDj/577lE9YWazpmPvHwPCXtOePtSCwJTnbyyGcvYKKxTWsSq8MglJy7 31 | uKKoa0ZGCIwqa3zu4vM4ng== 32 | -----END RSA PRIVATE KEY----- 33 | -------------------------------------------------------------------------------- /tests/run/certs/client-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIFewIBAAKCATEAv/0IYsxRwCYX3xjF3JF4PMibdgI+GxjFRm1LghgkKkI8DEN5 3 | WiiyskAT3AGIlK0Hp5LoXc5UZjKEIiAxP1BikL4K6UEvm3Nv6JubUB0ScWdkREp7 4 | vsw5rm3bJr51lgGm5HwWwV5/aavkWbzDDPHKZw8jL7/XUG/Zlj7ZyUmgqGSCni+l 5 | QQRbVMYViM9UhjfxpMcp7A1nqWSd2GLX7TD+XHbnnGDwTWy+eNwuzI7oRiio6hzw 6 | olcWW39x4VnWUuVnjMrZTze5i3WjYFw/0C+N3KRVEIZr/w3YhliMOiM98VAa5SOL 7 | 638pWzRnQjtSulQwTc/ySBjaRMVHMl6JPsMSfwx4yGJJz5QiLRzfbMpvoBeFFk6k 8 | cOxaxFF/t6d/JWc+QnGYnUWJolvZSIGWfXf8TQIDAQABAoIBL0denj9xX505NqaO 9 | Dv/FFBgvJZuOOd2Dgn0rzrtjPg53kNr+OkkfLU7A2KEbRiqpfVmjbb4cIEPdg5aB 10 | YSKoP1E5/ym25yZimLdfy9zRnImLuzpSdgNM6CRvsjLfmoFTxowplPaiqmVzVkVb 11 | ESc+uynp9qqe0OvrUyJckEQY8CBT54/me7Laa8PtNGl8qW87shi58QZPSrnX3LP/ 12 | Y7ojW0XngFsPWqmHBYxBWb3+PO/QuJYQzEb24E/E+4LOGuhTg8ylDqrcbnhzkHEH 13 | /XcG1sIltsHr6Ai20l+JG50KJ0zYMSGg48HuUZYegW+9AI8H7OgZIY8OlXHp5cuw 14 | lyZZeQm1/5EZIeirJoHp3dh42RkT5v44Xz1ocBMwZrdeuoJlmWHrbswTcKyO8Cfb 15 | UWvNXwKBmQDDg77I0O/7d4LlYEauP3adsG0mp+kV6tWxzMnv3c0aA8FkHUVoHK/9 16 | JWm+v5qJ5v3l8H9wA+non7RYcJjnATr4CtOnF3EFFDrcYL//nmWMJuayOtKiRhMq 17 | Dhub++qJaZm1lxaEt7KRaY7tQZ6ZrBo6EOWu0H0nky17xe3fFM93ORvWp7Mwkxkm 18 | b1BbtO/10JU0+sapWQdHTwKBmQD7YgUZRBTZcCHlvQ7u9oSnFM10pb2jBYxgSkiN 19 | 99cimwyeRcWo0fdOROBeUREJ/KgRHY9u97cnYqJ/y4AiB1zna8NDyC8JxVOVjy8J 20 | Psma6n7G0A5KVMgELM+Vif5onNu9bcOd13puG7igv3GOC80jQ/IJW0dhatDtxmjB 21 | bqNcMTN7lix/UPV6mpbAIpgwg1I4k1NuaZvbowKBmQC/zzVRwCFf/ByPucc91Yci 22 | Jt6+qMZ0OSISv81xJJG+LucAt/LKtDI30QeQGlubZOG8PxhXJY/KJzv/898d6kgW 23 | 5lBEwiugBvvEDqruNVB8kgGL40eX6dWNUa/mdNvgmZgx3Zs68xkdrYiJ3PGi44QL 24 | aV5cBbBzLeHWZxT54Wm0FnPoQDf8tKNc4KHehoFQEKUBB/H0XCJW4wKBmHxPBGZy 25 | HD1KDfklfHT+wqo8xzyfmR88ZyZWlXpezKv4ME00A4JwEfNKbAk33U0q+5E7JOqi 26 | 5Jc9V04Ku9oX+gEWcQDbxSb3xVV38LKJsfhBbV+zEt3+/snRvvUbwArLRn5uAQXU 27 | wF4ipzIWeXjcrRx7RP0LfkjWIWrzamn85Bt62RKMOITc7Acs2s84TDnxNn9zmxZG 28 | cyQxAoGZAI4mAR8HYlyTfFzN5L0e4dPrTQbXBZHD/B+gPdjrsy+3/mnkxumotvsa 29 | Wa4ruXXLlkUQ+enYryax+c1ZW/2AdQ0EDGKIdKy/RwzvLeS0ZhGKhC7CJVK2ezCC 30 | X3u+0MmYMPxT7cmFj8q6eRgNpzCbsANKSqpzX+52jiiQxR0bE+cfWCNy7yBBYJCy 31 | z0QrsAtohslE1CjcXeXb 32 | -----END RSA PRIVATE KEY----- 33 | -------------------------------------------------------------------------------- /tests/run/certs/server-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIFewIBAAKCATEA190qI8Ict55jeto3EumIxub2y/Ae9CWz5EAhUWQFVQc1IWxI 3 | l08Q2N2cFy89kagZ2DiDsScm6QZumiE/PyP7y5pXlSOn/DZ+p/K+i9LNznGHuEZQ 4 | qYLIXwhsI+xEMa+KP65NgM/vAnpn5ZdaJCSJR2pGL1Iajszix+n37M8jMMvEopo0 5 | Wjj+GjnIkm/PPLIfOXnrR+pBrE8np4p7JvcJnW3qFt+zy7GIo3f99wjkaMjEl0Eu 6 | d5DpF9n0VcRItRfNCRLLTT7IOfcl6M+/dWGa/pIuKdhpoNmwZxzdGc9hQDlr+QLT 7 | pW8M1xzx0Mfq0rJIOfSpSSXw007iwAqDYVd8D3Ai6zmVY5CjRypzyngiAYc02QZH 8 | o80U15JoC71lgh5RTFSopXDClgBJ0grMBNXvtwIDAQABAoIBMEKCbcfruI5oukzx 9 | bDOjCdYC9rqaRudBsJ4clkduEmiC2n9sTid0oIO5MC1CjG1TBneE3iqYnhgBN9W8 10 | dbC+JQg0C1Uz0b/XiIm1tLj/IBNCDqeb3qGD3rnNLgiZdN98LxP04ANWzdUNIvLu 11 | AcOOEFAVMf/Fg9JI1Xz0HUP1BGo19mWFLqk30y8Aa8iWs5sHZLCAXJphVo/AmGZW 12 | GgpHXGohNeEuafE85J36qSXiyQ/J2kglWXdT0h1hbAyIRmN7BakOou1TAlDz9+2a 13 | IujOZgQrEnSeZlKv7aUKTUpTE4kwoKOQLZ3YB7cRma3CaDoZ6dSyDC9a1zTNeLjz 14 | sS0wn/46O+QkYQxNoxiBHj6vzWWplC+y6/c+7UZF5NDfogSQ7BZEKHiKK0zu1xTW 15 | 8fQ3C8UCgZkA2J3qbwdi/Jtg22RSceIyaTwhe2UVhF9PKljx304vmH2lvbBEklHP 16 | eiB98FOLlu6AgxWqOi/BokFRzJHMszCRPCZFes4sbzts4PKiX8PAGVdoHXYjPdak 17 | lerAxS7W/lK5cn5wQyUsc7ljb45rA/J8T8tQ89o4qRMicGa/MHxagJVvUVX0Xev6 18 | 3qPUTb8SOB1ye2oB5uSCxVUCgZkA/xw0abUUCFLYnWbxZjNshqK8r8KabviBsk5j 19 | 4Li4UxQOzticw9k9UU3Ct9hgcQ8jVKBLXTxT+cwKCrc3ZTWwRrOkHct1IQM7L5hk 20 | LX5BKL6+XDaJCbRwr9+zkopOJ3TUOdFo7pWDJgRjTWhnYTMgSf+14/hceoD1KKMM 21 | aik3ru/FwJkQYFYLtNj3V1j4VuVHSOyOqbcaoNsCgZhMV3M8yBSpxDThfTzVKAvu 22 | LKP8MgbgTRrAaPJtace6bWXRMWMpUi3V88eOwFLs0Yd3K1aABT6v6WdjumqzKEW3 23 | NiG8gxcD6KSZrsltCLcV90kZQP5wl8oPj9l6ZOSeYxc6c7cq4toEuuyBb2bl0Drh 24 | gF06Y8keRUEY7g0pkFnxATlnJ+zkgPs8Je73q4RHRJGJTzX2Ysh3tQKBmQDe8A79 25 | sbjn7T5Pj362CYp1vhGWp0G+aH0vDUJLSCIMuCKYsMOOg3IKcyIO95CQPOJrOgmi 26 | WO4qBh1gb+yBDgIWRzbMstiRGPnIBizFdOgMa2R/wUjQqlcv2xZaoXLbGEW+oTpK 27 | BW6u8na1Vt/BGaTGBik2J/zpMXkNIi/fNlXrEq6GOT0OcyOXz2OXebDMf2FkYRXr 28 | SpCCsQKBmDbHnS3b4mQH7I6hDVCYT7zyQeyEwMjufkf/vnbsh4V6J5Sq2gtd9epl 29 | qsKCCTPZaGdkZoOO7CGFJawlzm7Htm9Y1bmZUTBHz61x/+cDPp8IL6qAMod23WSD 30 | 8R/Rv9nJLJqH+LnQ/Bvfwl2eKyJquinbTgirdmdyDkmbsKJfHOKcCBtAYSnGWBg0 31 | hag+Jq3uH47luVKswO+V 32 | -----END RSA PRIVATE KEY----- 33 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I support 2 | SUBDIRS = . man doc tests systemd 3 | bin_PROGRAMS = nbd-server nbd-trdump nbd-trplay 4 | EXTRA_PROGRAMS = nbd-client make-integrityhuge 5 | noinst_LTLIBRARIES = libnbdsrv.la libcliserv.la libnbdclt.la 6 | libcliserv_la_SOURCES = cliserv.h cliserv.c 7 | libcliserv_la_CFLAGS = @CFLAGS@ 8 | client_srcs = nbd-client.c cliserv.h nbd-netlink.h 9 | nbd_server_SOURCES = nbd-server.c cliserv.h lfs.h nbd.h nbdsrv.h backend.h \ 10 | netdb-compat.h nbd-helper.h 11 | nbd_trdump_SOURCES = nbd-trdump.c cliserv.h nbd.h 12 | nbd_trplay_SOURCES = nbd-trplay.c cliserv.h nbd.h 13 | client_flags = @CFLAGS@ 14 | nbd_server_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ 15 | nbd_trdump_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ 16 | nbd_trplay_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ 17 | libnbdsrv_la_SOURCES = nbdsrv.c nbdsrv.h treefiles.c treefiles.h 18 | libnbdsrv_la_CFLAGS = @CFLAGS@ @GLIB_CFLAGS@ 19 | client_libs = libcliserv.la libnbdclt.la 20 | nbd_server_LDADD = @GLIB_LIBS@ libnbdsrv.la libcliserv.la 21 | nbd_trdump_LDADD = libcliserv.la 22 | nbd_trplay_LDADD = libcliserv.la 23 | make_integrityhuge_SOURCES = make-integrityhuge.c cliserv.h nbd.h nbd-debug.h 24 | EXTRA_DIST = maketr CodingStyle autogen.sh README.md support/genver.sh 25 | if GNUTLS 26 | nbd_server_CFLAGS += @GnuTLS_CFLAGS@ 27 | nbd_server_LDADD += @GnuTLS_LIBS@ 28 | endif 29 | if CLIENT 30 | sbin_PROGRAMS = nbd-client 31 | if GNUTLS 32 | sbin_PROGRAMS += min-nbd-client 33 | min_nbd_client_SOURCES = $(client_srcs) 34 | min_nbd_client_CFLAGS = $(client_flags) -DNOTLS -DPROG_NAME='"min-nbd-client"' 35 | min_nbd_client_LDADD = $(client_libs) 36 | nbd_client_SOURCES = $(client_srcs) crypto-gnutls.c crypto-gnutls.h buffer.c buffer.h 37 | nbd_client_CFLAGS = $(client_flags) @GnuTLS_CFLAGS@ -DPROG_NAME='"nbd-client"' 38 | nbd_client_LDADD = $(client_libs) @GnuTLS_LIBS@ 39 | else 40 | nbd_client_SOURCES = $(client_srcs) 41 | nbd_client_CFLAGS = $(client_flags) -DNOTLS -DPROG_NAME='"nbd-client"' 42 | nbd_client_LDADD = $(client_libs) 43 | endif 44 | endif 45 | 46 | libnbdclt_la_SOURCES = nbdtab_parser.tab.h nbdtab_parser.y nbdtab_lexer.l nbdclt.h 47 | BUILT_SOURCES = nbdtab_parser.tab.h 48 | 49 | nbd-client.c: $(builddir)/nbdtab_parser.tab.h 50 | nbdtab_parser.tab.h: $(srcdir)/nbdtab_parser.y 51 | bison -d $^ > $@ 52 | 53 | AM_DISTCHECK_CONFIGURE_FLAGS=--enable-syslog 54 | 55 | if NETLINK 56 | bin_PROGRAMS += nbd-get-status 57 | nbd_get_status_SOURCES = nbd-get-status.c cliserv.c 58 | nbd_get_status_CFLAGS = @CFLAGS@ 59 | endif 60 | -------------------------------------------------------------------------------- /make-integrityhuge.c: -------------------------------------------------------------------------------- 1 | /* 2 | * make-integrityhuge 3 | * 4 | * Make a file to test oversize writes 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "config.h" 15 | #include "cliserv.h" 16 | #include "nbd.h" 17 | 18 | const uint64_t filesize=50*1000*1000; 19 | const uint64_t transactions = 250; 20 | 21 | static inline void dowrite(int f, void *buf, size_t len) { 22 | ssize_t res; 23 | 24 | while(len>0) { 25 | if((res=write(f, buf, len)) <=0) { 26 | perror ("Error writing transactions"); 27 | exit(1); 28 | } 29 | len-=res; 30 | buf+=res; 31 | } 32 | } 33 | 34 | static inline uint64_t getrandomuint64() { 35 | uint64_t r=0; 36 | int i; 37 | /* RAND_MAX may be as low as 2^15 */ 38 | for (i= 1 ; i<=5; i++) 39 | r ^= random() ^ (r << 15); 40 | return r; 41 | } 42 | 43 | int main(int argc, char**argv) { 44 | struct nbd_request req; 45 | struct nbd_reply rep; 46 | uint64_t handle; 47 | int writefd = 1; /*stdout*/ 48 | 49 | req.magic = htonl(NBD_REQUEST_MAGIC); 50 | rep.magic = htonl(NBD_REPLY_MAGIC); 51 | rep.error = 0; 52 | 53 | for (handle = 0; handle < transactions; handle++) 54 | { 55 | uint64_t offset; 56 | uint64_t length; 57 | uint64_t flags; 58 | uint32_t command; 59 | 60 | /* make the length between 0x400 and the length of the disk -08x800, with all 61 | * the bottom bits clear */ 62 | length = ((getrandomuint64() % (filesize-0x800)) & ~((uint64_t)0x3ff)) + 0x400; 63 | /* generate an offset that will fit the length */ 64 | offset = (getrandomuint64() % (filesize-length)) & ~((uint64_t)0x3ff); 65 | flags = getrandomuint64(); 66 | 67 | command = (flags & 0x01)?NBD_CMD_READ:NBD_CMD_WRITE; 68 | 69 | if (!(flags & 0x0f)) 70 | command = NBD_CMD_FLAG_FUA | NBD_CMD_WRITE; 71 | 72 | if (!(flags & 0xf0)) { 73 | offset = 0; 74 | length = 0; 75 | command = NBD_CMD_FLUSH; 76 | } 77 | 78 | *(uint64_t *)(req.handle) = htonll(handle); 79 | *(uint64_t *)(rep.handle) = htonll(handle); 80 | req.type = htonl(command); 81 | req.from = htonll(offset); 82 | req.len = htonl(length); 83 | 84 | dowrite(writefd, &req, sizeof(req)); 85 | dowrite(writefd, &rep, sizeof(rep)); 86 | } 87 | 88 | req.type = htonl(NBD_CMD_DISC); 89 | req.from = 0; 90 | req.len = 0; 91 | dowrite(writefd, &req, sizeof(req)); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /tests/parse/parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "nbdtab_parser.tab.h" 7 | #include 8 | #include 9 | 10 | CLIENT client_empty; 11 | CLIENT client_noopts = { 12 | .name = "test", 13 | .dev = "nbd0", 14 | .hostn = "localhost", 15 | }; 16 | 17 | CLIENT client_singleopt = { 18 | .name = "test", 19 | .dev = "nbd0", 20 | .hostn = "localhost", 21 | .bs = 1024, 22 | }; 23 | 24 | CLIENT client_multiopt = { 25 | .name = "test", 26 | .dev = "nbd0", 27 | .hostn = "localhost", 28 | .bs = 1024, 29 | .no_optgo = true, 30 | }; 31 | 32 | CLIENT client_ipv6 = { 33 | .name = "test", 34 | .dev = "nbd0", 35 | .hostn = "2a01:4f8:200:91e8::2", 36 | }; 37 | 38 | CLIENT client_ipv4 = { 39 | .name = "test", 40 | .dev = "nbd0", 41 | .hostn = "192.168.1.1", 42 | }; 43 | 44 | CLIENT *cur_client; 45 | bool seen_commit = false; 46 | 47 | void nbdtab_set_property(char *property, char *val) { 48 | printf("property %s set to %s\n", property, val); 49 | assert(strcmp(property, "bs") == 0); 50 | assert(cur_client->bs == strtol(val, NULL, 10)); 51 | } 52 | 53 | void nbdtab_set_flag(char *property) { 54 | printf("flag %s set\n", property); 55 | assert(strcmp(property, "no_optgo") == 0); 56 | assert(cur_client->no_optgo == true); 57 | } 58 | 59 | void nbdtab_commit_line(char *devn, char *hostn, char *exportname) { 60 | printf("finishing line with device %s, hostname %s, exportname %s\n", devn, hostn, exportname); 61 | assert(strcmp(cur_client->dev, devn) == 0); 62 | assert(strcmp(cur_client->hostn, hostn) == 0); 63 | assert(strcmp(cur_client->name, exportname) == 0); 64 | seen_commit = true; 65 | } 66 | 67 | void yyerror(char *s) { 68 | fprintf(stderr, "%s\n", s); 69 | } 70 | 71 | extern FILE *yyin, *yyout; 72 | 73 | int main(int argc, char**argv) { 74 | printf("testing %s\n", argv[1]); 75 | yyin = fopen(argv[1], "r"); 76 | yyout = fopen("/dev/null", "w"); 77 | char *which = strrchr(argv[1], '/'); 78 | if(which) { 79 | which++; 80 | } else { 81 | which = argv[1]; 82 | } 83 | 84 | #define KNOW_CONF(x) if(!strcmp(which, #x)) cur_client = &client_##x; 85 | 86 | KNOW_CONF(empty); 87 | KNOW_CONF(noopts); 88 | KNOW_CONF(singleopt); 89 | KNOW_CONF(multiopt); 90 | KNOW_CONF(ipv6); 91 | KNOW_CONF(ipv4); 92 | 93 | #undef KNOW_CONF 94 | 95 | assert(cur_client != NULL); 96 | 97 | yyparse(); 98 | 99 | assert(cur_client == &client_empty || seen_commit == true); 100 | } 101 | -------------------------------------------------------------------------------- /tests/run/certs/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test certificates used for NBD's test suite. 2 | 3 | They are: 4 | 5 | * `client-key.pem` - client private key 6 | * `client-cert.pem` - client public key 7 | * `server-key.pem` - server private key 8 | * `server-cert.pem` - server public key 9 | * `ca-key.pem` - certificate authority private key 10 | * `ca-cert.pem` - certificate authority public key 11 | 12 | The `*.info` files are generated using the procedure below. 13 | 14 | Certificates can be made using the procedure at: https://qemu.weilnetz.de/qemu-doc.html 15 | using GnuTLS's certtool tool. 16 | 17 | Here's how: 18 | 19 | First make a CA: 20 | 21 | # certtool --generate-privkey > ca-key.pem 22 | 23 | And give it a public key: 24 | 25 | # cat > ca.info < server.info < server-key.pem 42 | # certtool --generate-certificate --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --load-privkey server-key.pem --template server.info --outfile server-cert.pem 43 | 44 | Note the `cn` needs to match the hostname that nbd-client uses to connect (or the hostname specified with `-H` on the command line). 45 | 46 | And finally issue a client certificate: 47 | 48 | # cat > client.info < client-key.pem 59 | # certtool --generate-certificate --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --load-privkey client-key.pem --template client.info --outfile client-cert.pem 60 | 61 | 62 | In contrast to the other files in this repository, the contents of this directory 63 | are not licensed under the GPLv2. To the extent possible by applicable law, I 64 | hereby waive all copyright and related or neighboring rights to the files in this 65 | directory and release them into the public domain. 66 | 67 | The purpose of releasing this into the public domain is to allow 68 | competing implementations of the NBD protocol without those 69 | implementations being considered derivative implementations. 70 | -------------------------------------------------------------------------------- /nbd-netlink.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* 3 | * Copyright (C) 2017 Facebook. All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public 7 | * License v2 as published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 021110-1307, USA. 18 | */ 19 | #ifndef _UAPILINUX_NBD_NETLINK_H 20 | #define _UAPILINUX_NBD_NETLINK_H 21 | 22 | #define NBD_GENL_FAMILY_NAME "nbd" 23 | #define NBD_GENL_VERSION 0x1 24 | #define NBD_GENL_MCAST_GROUP_NAME "nbd_mc_group" 25 | 26 | /* Configuration policy attributes, used for CONNECT */ 27 | enum { 28 | NBD_ATTR_UNSPEC, 29 | NBD_ATTR_INDEX, 30 | NBD_ATTR_SIZE_BYTES, 31 | NBD_ATTR_BLOCK_SIZE_BYTES, 32 | NBD_ATTR_TIMEOUT, 33 | NBD_ATTR_SERVER_FLAGS, 34 | NBD_ATTR_CLIENT_FLAGS, 35 | NBD_ATTR_SOCKETS, 36 | NBD_ATTR_DEAD_CONN_TIMEOUT, 37 | NBD_ATTR_DEVICE_LIST, 38 | NBD_ATTR_BACKEND_IDENTIFIER, 39 | __NBD_ATTR_MAX, 40 | }; 41 | #define NBD_ATTR_MAX (__NBD_ATTR_MAX - 1) 42 | 43 | /* 44 | * This is the format for multiple devices with NBD_ATTR_DEVICE_LIST 45 | * 46 | * [NBD_ATTR_DEVICE_LIST] 47 | * [NBD_DEVICE_ITEM] 48 | * [NBD_DEVICE_INDEX] 49 | * [NBD_DEVICE_CONNECTED] 50 | */ 51 | enum { 52 | NBD_DEVICE_ITEM_UNSPEC, 53 | NBD_DEVICE_ITEM, 54 | __NBD_DEVICE_ITEM_MAX, 55 | }; 56 | #define NBD_DEVICE_ITEM_MAX (__NBD_DEVICE_ITEM_MAX - 1) 57 | 58 | enum { 59 | NBD_DEVICE_UNSPEC, 60 | NBD_DEVICE_INDEX, 61 | NBD_DEVICE_CONNECTED, 62 | __NBD_DEVICE_MAX, 63 | }; 64 | #define NBD_DEVICE_ATTR_MAX (__NBD_DEVICE_MAX - 1) 65 | 66 | /* 67 | * This is the format for multiple sockets with NBD_ATTR_SOCKETS 68 | * 69 | * [NBD_ATTR_SOCKETS] 70 | * [NBD_SOCK_ITEM] 71 | * [NBD_SOCK_FD] 72 | * [NBD_SOCK_ITEM] 73 | * [NBD_SOCK_FD] 74 | */ 75 | enum { 76 | NBD_SOCK_ITEM_UNSPEC, 77 | NBD_SOCK_ITEM, 78 | __NBD_SOCK_ITEM_MAX, 79 | }; 80 | #define NBD_SOCK_ITEM_MAX (__NBD_SOCK_ITEM_MAX - 1) 81 | 82 | enum { 83 | NBD_SOCK_UNSPEC, 84 | NBD_SOCK_FD, 85 | __NBD_SOCK_MAX, 86 | }; 87 | #define NBD_SOCK_MAX (__NBD_SOCK_MAX - 1) 88 | 89 | enum { 90 | NBD_CMD_UNSPEC, 91 | NBD_CMD_CONNECT, 92 | NBD_CMD_DISCONNECT, 93 | NBD_CMD_RECONFIGURE, 94 | NBD_CMD_LINK_DEAD, 95 | NBD_CMD_STATUS, 96 | __NBD_CMD_MAX, 97 | }; 98 | #define NBD_CMD_MAX (__NBD_CMD_MAX - 1) 99 | 100 | #endif /* _UAPILINUX_NBD_NETLINK_H */ 101 | -------------------------------------------------------------------------------- /nbd-get-status.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "lfs.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "cliserv.h" 9 | #include "nbd-netlink.h" 10 | 11 | static struct nla_policy nbd_device_policy[NBD_DEVICE_ATTR_MAX + 1] = { 12 | [NBD_DEVICE_INDEX] = { .type = NLA_U32 }, 13 | [NBD_DEVICE_CONNECTED] = { .type = NLA_U8 }, 14 | }; 15 | 16 | static struct nl_sock *get_nbd_socket(int *driver_id) 17 | { 18 | struct nl_sock *socket; 19 | int id; 20 | 21 | socket = nl_socket_alloc(); 22 | if (!socket) 23 | err("Couldn't allocate netlink socket\n"); 24 | 25 | if (genl_connect(socket)) 26 | err("Couldn't connect to the generic netlink socket\n"); 27 | id = genl_ctrl_resolve(socket, "nbd"); 28 | if (id < 0) 29 | err("Couldn't resolve the nbd netlink family, make sure the nbd module is loaded and your nbd driver supports the netlink interface.\n"); 30 | if (driver_id) 31 | *driver_id = id; 32 | return socket; 33 | } 34 | 35 | static int callback(struct nl_msg *msg, void *arg) 36 | { 37 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 38 | struct nlattr *msg_attr[NBD_ATTR_MAX + 1]; 39 | struct nlattr *attr; 40 | int ret, rem; 41 | 42 | ret = nla_parse(msg_attr, NBD_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 43 | genlmsg_attrlen(gnlh, 0), NULL); 44 | if (ret) 45 | err("Invalid response from get status?\n"); 46 | 47 | nla_for_each_nested(attr, msg_attr[NBD_ATTR_DEVICE_LIST], rem) { 48 | struct nlattr *device[NBD_DEVICE_ATTR_MAX + 1]; 49 | u32 index; 50 | uint8_t connected; 51 | 52 | if (nla_type(attr) != NBD_DEVICE_ITEM) 53 | err("Invalid attr type in the device list\n"); 54 | ret = nla_parse_nested(device, NBD_DEVICE_ATTR_MAX, attr, 55 | nbd_device_policy); 56 | if (ret) 57 | err("Invalid attr device attr\n"); 58 | index = nla_get_u32(device[NBD_DEVICE_INDEX]); 59 | connected = nla_get_u8(device[NBD_DEVICE_CONNECTED]); 60 | printf("/dev/nbd%d: %s\n", (int)index, 61 | connected ? "connected" : "disconnected"); 62 | } 63 | return NL_OK; 64 | } 65 | 66 | int main(int argc, char **argv) 67 | { 68 | struct nl_sock *socket; 69 | struct nlattr *sock_attr; 70 | struct nl_msg *msg; 71 | int driver_id; 72 | int index = -1; 73 | 74 | if (argc > 1) { 75 | if (sscanf(argv[1], "/dev/nbd%d", &index) != 1) 76 | err("Invalid nbd device target\n"); 77 | } 78 | 79 | socket = get_nbd_socket(&driver_id); 80 | nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL); 81 | 82 | msg = nlmsg_alloc(); 83 | if (!msg) 84 | err("Couldn't allocate netlink message\n"); 85 | genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0, 86 | NBD_CMD_STATUS, 0); 87 | if (index >= 0) 88 | NLA_PUT_U32(msg, NBD_ATTR_INDEX, index); 89 | if (nl_send_sync(socket, msg) < 0) 90 | err("Failed to get status\n"); 91 | return 0; 92 | nla_put_failure: 93 | err("Failed to create netlink message\n"); 94 | } 95 | -------------------------------------------------------------------------------- /treefiles.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include // for PATH_MAX 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | #include "cliserv.h" 11 | #include "treefiles.h" 12 | #include "nbd-debug.h" 13 | 14 | /** 15 | * Tree structure helper functions 16 | */ 17 | void construct_path(char* name, int lenmax, off_t size, off_t pos, off_t* ppos) { 18 | if (lenmax<10) 19 | err("Char buffer overflow. This is likely a bug."); 20 | 21 | if (size0) { 91 | unlink(tmpname); /* File will stick around whilst FD open */ 92 | } else { 93 | err("Error opening tree block file %m"); 94 | } 95 | } 96 | char* n = "\0"; 97 | if(lseek(handle,TREEPAGESIZE-1, SEEK_SET) < 0) { 98 | err("Could not create tree file!\n"); 99 | } 100 | ssize_t c = write(handle,n,1); 101 | if (c<1) { 102 | err("Error setting tree block file size %m"); 103 | } 104 | } 105 | pthread_mutex_unlock(mutex); 106 | return handle; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /man/nbd-trplay.1.sgml.in: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | --> 11 | 12 | 13 | Manfred"> 14 | Spraul"> 15 | 16 | $Date$"> 17 | 19 | 1"> 20 | manfred@de.bosch.com"> 21 | 22 | nbd-trplay"> 23 | 24 | 25 | Debian GNU/Linux"> 26 | GNU"> 27 | ]> 28 | 29 | 30 | 31 |
32 | &dhemail; 33 |
34 | 35 | &dhfirstname; 36 | &dhsurname; 37 | 38 | 39 | 2001 40 | &dhusername; 41 | 42 | &dhdate; 43 |
44 | 45 | &dhucpackage; 46 | 47 | &dhsection; 48 | 49 | 50 | &dhpackage; 51 | 52 | replay all or parts of an nbd transaction log 53 | 54 | 55 | 56 | &dhpackage; 57 | 58 | 59 | 60 | DESCRIPTION 61 | 62 | &dhpackage; replays all or parts of 63 | a transaction log produced by nbd-server 64 | (specifically by the transactionlog 65 | configuration directive with the option datalog 66 | ). 67 | 68 | See nbd-trplay --help for the command line parameters. 69 | 70 | 71 | 72 | OUTPUT 73 | 74 | The file updates the image provided via -i. 75 | 76 | 77 | 78 | SEE ALSO 79 | 80 | nbd-server (1). 81 | 82 | 83 | 84 | AUTHOR 85 | The NBD kernel module and the NBD tools have been written by 86 | Pavel Macheck (pavel@ucw.cz). 87 | 88 | The kernel module is now maintained by Paul Clements 89 | (Paul.Clements@steeleye.com), while the userland tools are maintained by 90 | Wouter Verhelst (wouter@debian.org) 91 | 92 | This manual page was written by &dhusername; (&dhemail;) for 93 | the &debian; system (but may be used by others). Permission is 94 | granted to copy, distribute and/or modify this document under the 95 | terms of the GNU General Public License, 96 | version 2, as published by the Free Software Foundation. 97 | 98 | 99 |
100 | -------------------------------------------------------------------------------- /cliserv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | const u64 cliserv_magic = 0x00420281861253LL; 13 | const u64 opts_magic = 0x49484156454F5054LL; 14 | const u64 rep_magic = 0x3e889045565a9LL; 15 | 16 | /** 17 | * Set a socket to blocking or non-blocking 18 | * 19 | * @param fd The socket's FD 20 | * @param nb nonzero to set to non-blocking, else 0 to set to blocking 21 | * @return 0 - OK, -1 failed 22 | */ 23 | int set_nonblocking(int fd, int nb) { 24 | int sf = fcntl (fd, F_GETFL, 0); 25 | if (sf == -1) 26 | return -1; 27 | return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK)); 28 | } 29 | 30 | 31 | void setmysockopt(int sock) { 32 | int size = 1; 33 | #if 0 34 | if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) 35 | INFO("(no sockopt/1: %m)"); 36 | #endif 37 | #ifdef IPPROTO_TCP 38 | size = 1; 39 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &size, sizeof(int)) < 0) 40 | INFO("(no sockopt/2: %m)"); 41 | #endif 42 | #if 0 43 | size = 1024; 44 | if (setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0) 45 | INFO("(no sockopt/3: %m)"); 46 | #endif 47 | } 48 | 49 | void err_nonfatal(const char *s) { 50 | char s1[150], *s2; 51 | 52 | strncpy(s1, s, sizeof(s1)); 53 | if ((s2 = strstr(s, "%m"))) { 54 | strncpy(s1 + (s2 - s), strerror(errno), sizeof(s1) - (s2 - s)); 55 | s2 += 2; 56 | strncpy(s1 + strlen(s1), s2, sizeof(s1) - strlen(s1)); 57 | } 58 | #ifndef sun 59 | /* Solaris doesn't have %h in syslog */ 60 | else if ((s2 = strstr(s, "%h"))) { 61 | strncpy(s1 + (s2 - s), hstrerror(h_errno), sizeof(s1) - (s2 - s)); 62 | s2 += 2; 63 | strncpy(s1 + strlen(s1), s2, sizeof(s1) - strlen(s1)); 64 | } 65 | #endif 66 | 67 | s1[sizeof(s1)-1] = '\0'; 68 | #ifdef ISSERVER 69 | syslog(LOG_ERR, "%s", s1); 70 | syslog(LOG_ERR, "Exiting."); 71 | #endif 72 | fprintf(stderr, "Error: %s\n", s1); 73 | } 74 | 75 | void nbd_err(const char *s) { 76 | err_nonfatal(s); 77 | fprintf(stderr, "Exiting.\n"); 78 | exit(EXIT_FAILURE); 79 | } 80 | 81 | void nbd_err_code(const char *s, int code) { 82 | err_nonfatal(s); 83 | fprintf(stderr, "Exiting.\n"); 84 | exit(abs(code)); 85 | } 86 | 87 | void logging(const char* name) { 88 | #ifdef ISSERVER 89 | openlog(name, LOG_PID, LOG_DAEMON); 90 | #endif 91 | setvbuf(stdout, NULL, _IONBF, 0); 92 | setvbuf(stderr, NULL, _IONBF, 0); 93 | } 94 | 95 | #ifndef ntohll 96 | #ifdef WORDS_BIGENDIAN 97 | uint64_t ntohll(uint64_t a) { 98 | return a; 99 | } 100 | #else 101 | uint64_t ntohll(uint64_t a) { 102 | u32 lo = a & 0xffffffff; 103 | u32 hi = a >> 32U; 104 | lo = ntohl(lo); 105 | hi = ntohl(hi); 106 | return ((uint64_t) lo) << 32U | hi; 107 | } 108 | #endif 109 | #endif 110 | 111 | /** 112 | * Read data from a file descriptor into a buffer 113 | * 114 | * @param f a file descriptor 115 | * @param buf a buffer 116 | * @param len the number of bytes to be read 117 | * @return 0 on completion, or -1 on failure 118 | **/ 119 | int readit(int f, void *buf, size_t len) { 120 | ssize_t res; 121 | while (len > 0) { 122 | DEBUG("*"); 123 | res = read(f, buf, len); 124 | if (res > 0) { 125 | len -= res; 126 | buf += res; 127 | } else if (res < 0) { 128 | if(errno != EAGAIN) { 129 | err_nonfatal("Read failed: %m"); 130 | return -1; 131 | } 132 | } else { 133 | errno = ECONNRESET; 134 | return -1; 135 | } 136 | } 137 | return 0; 138 | } 139 | 140 | /** 141 | * Write data from a buffer into a filedescriptor 142 | * 143 | * @param f a file descriptor 144 | * @param buf a buffer containing data 145 | * @param len the number of bytes to be written 146 | * @return 0 on success, or -1 if the socket was closed 147 | **/ 148 | int writeit(int f, const void *buf, size_t len) { 149 | ssize_t res; 150 | while (len > 0) { 151 | DEBUG("+"); 152 | if ((res = write(f, buf, len)) <= 0) { 153 | switch(errno) { 154 | case EAGAIN: 155 | break; 156 | default: 157 | err_nonfatal("Send failed: %m"); 158 | return -1; 159 | } 160 | } 161 | len -= res; 162 | buf += res; 163 | } 164 | return 0; 165 | } 166 | -------------------------------------------------------------------------------- /nbd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 1999 Copyright (C) Pavel Machek, pavel@ucw.cz. This code is GPL. 3 | * 1999/11/04 Copyright (C) 1999 VMware, Inc. (Regis "HPReg" Duchesne) 4 | * Made nbd_end_request() use the io_request_lock 5 | * 2001 Copyright (C) Steven Whitehouse 6 | * New nbd_end_request() for compatibility with new linux block 7 | * layer code. 8 | * 2003/06/24 Louis D. Langholtz 9 | * Removed unneeded blksize_bits field from nbd_device struct. 10 | * Cleanup PARANOIA usage & code. 11 | * 2004/02/19 Paul Clements 12 | * Removed PARANOIA, plus various cleanup and comments 13 | */ 14 | 15 | #ifndef LINUX_NBD_H 16 | #define LINUX_NBD_H 17 | 18 | //#include 19 | 20 | #define NBD_SET_SOCK _IO( 0xab, 0 ) 21 | #define NBD_SET_BLKSIZE _IO( 0xab, 1 ) 22 | #define NBD_SET_SIZE _IO( 0xab, 2 ) 23 | #define NBD_DO_IT _IO( 0xab, 3 ) 24 | #define NBD_CLEAR_SOCK _IO( 0xab, 4 ) 25 | #define NBD_CLEAR_QUE _IO( 0xab, 5 ) 26 | #define NBD_PRINT_DEBUG _IO( 0xab, 6 ) 27 | #define NBD_SET_SIZE_BLOCKS _IO( 0xab, 7 ) 28 | #define NBD_DISCONNECT _IO( 0xab, 8 ) 29 | #define NBD_SET_TIMEOUT _IO( 0xab, 9 ) 30 | #define NBD_SET_FLAGS _IO( 0xab, 10 ) 31 | 32 | enum { 33 | NBD_CMD_READ = 0, 34 | NBD_CMD_WRITE = 1, 35 | NBD_CMD_DISC = 2, 36 | NBD_CMD_FLUSH = 3, 37 | NBD_CMD_TRIM = 4, 38 | NBD_CMD_CACHE = 5, 39 | NBD_CMD_WRITE_ZEROES = 6, 40 | NBD_CMD_BLOCK_STATUS = 7, 41 | NBD_CMD_RESIZE = 8 42 | }; 43 | 44 | #define NBD_CMD_MASK_COMMAND 0x0000ffff 45 | #define NBD_CMD_SHIFT (16) 46 | #define NBD_CMD_FLAG_FUA ((1 << 0) << NBD_CMD_SHIFT) 47 | #define NBD_CMD_FLAG_NO_HOLE ((1 << 1) << NBD_CMD_SHIFT) 48 | #define NBD_CMD_FLAG_DF ((1 << 2) << NBD_CMD_SHIFT) 49 | 50 | /* values for flags field */ 51 | #define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ 52 | #define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */ 53 | #define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */ 54 | #define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */ 55 | #define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ 56 | #define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ 57 | #define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */ 58 | #define NBD_FLAG_SEND_DF (1 << 7) /* Send NBD_CMD_FLAG_DF */ 59 | #define NBD_FLAG_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */ 60 | 61 | #define nbd_cmd(req) ((req)->cmd[0]) 62 | 63 | /* userspace doesn't need the nbd_device structure */ 64 | 65 | /* These are sent over the network in the request/reply magic fields */ 66 | 67 | #define NBD_REQUEST_MAGIC 0x25609513 68 | #define NBD_REPLY_MAGIC 0x67446698 69 | #define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef 70 | 71 | /* for the trace log, not part of the protocol, not sent over the wire */ 72 | #define NBD_TRACELOG_MAGIC 0x25609514 73 | 74 | #define NBD_OPT_REPLY_MAGIC 0x3e889045565a9LL 75 | 76 | #define NBD_REPLY_TYPE_NONE (0) 77 | #define NBD_REPLY_TYPE_OFFSET_DATA (1) 78 | #define NBD_REPLY_TYPE_OFFSET_HOLE (2) 79 | #define NBD_REPLY_TYPE_BLOCK_STATUS (3) 80 | 81 | #define NBD_REPLY_TYPE_ERROR ((1 << 15) + 1) 82 | #define NBD_REPLY_TYPE_ERROR_OFFSET ((1 << 15) + 2) 83 | 84 | #define NBD_REPLY_FLAG_DONE (1 << 0) 85 | 86 | /* 87 | * This is the packet used for communication between client and 88 | * server. All data are in network byte order. 89 | */ 90 | struct nbd_request { 91 | uint32_t magic; 92 | uint32_t type; /* == READ || == WRITE */ 93 | uint64_t cookie; 94 | uint64_t from; 95 | uint32_t len; 96 | } __attribute__ ((packed)); 97 | 98 | /* 99 | * This is the reply packet that nbd-server sends back to the client after 100 | * it has completed an I/O request (or an error occurs). 101 | */ 102 | struct nbd_reply { 103 | uint32_t magic; 104 | uint32_t error; /* 0 = ok, else error */ 105 | uint64_t cookie; /* cookie you got from request */ 106 | } __attribute__ ((packed)); 107 | 108 | /* 109 | * The reply packet for structured replies 110 | */ 111 | struct nbd_structured_reply { 112 | uint32_t magic; 113 | uint16_t flags; 114 | uint16_t type; 115 | uint64_t cookie; 116 | uint32_t paylen; 117 | } __attribute__ ((packed)); 118 | 119 | struct nbd_structured_error_payload { 120 | uint32_t error; 121 | uint16_t msglen; 122 | } __attribute__ ((packed)); 123 | 124 | #define NBD_EPERM 1 125 | #define NBD_EIO 5 126 | #define NBD_ENOMEM 12 127 | #define NBD_EINVAL 22 128 | #define NBD_ENOSPC 28 129 | #define NBD_EOVERFLOW 75 130 | #define NBD_ENOTSUP 95 131 | #define NBD_ESHUTDOWN 108 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /nbd-trdump.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nbd-trdump.c 3 | * 4 | * Takes an nbd transaction log file on stdin and translates it into something 5 | * comprehensible 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "config.h" 17 | /* We don't want to do syslog output in this program */ 18 | #undef ISSERVER 19 | #include "cliserv.h" 20 | #include "nbd.h" 21 | #include "nbd-helper.h" 22 | 23 | #define BUFSIZE 131072 24 | static char tmpbuf[BUFSIZE]; 25 | 26 | static bool g_with_datalog = false; 27 | 28 | static inline void doread(int f, void *buf, size_t len) { 29 | ssize_t res; 30 | 31 | while(len>0) { 32 | if((res=read(f, buf, len)) <=0) { 33 | if (!res) 34 | exit(0); 35 | perror ("Error reading transactions"); 36 | exit(1); 37 | } 38 | len-=res; 39 | buf+=res; 40 | } 41 | } 42 | 43 | int main(int argc, char**argv) { 44 | struct nbd_request req; 45 | struct nbd_reply rep; 46 | struct nbd_structured_reply srep; 47 | uint32_t magic; 48 | uint64_t cookie; 49 | uint32_t error; 50 | uint32_t command; 51 | uint32_t len; 52 | uint64_t offset; 53 | uint16_t flags; 54 | uint16_t type; 55 | uint32_t paylen; 56 | const char * ctext; 57 | int readfd = 0; /* stdin */ 58 | 59 | if(argc > 1) { 60 | int retval=0; 61 | if(strcmp(argv[1], "--help") && strcmp(argv[1], "-h")) { 62 | printf("E: unknown option %s.\n", argv[1]); 63 | retval=1; 64 | } 65 | printf("This is nbd-trdump, part of nbd %s.\n", PACKAGE_VERSION); 66 | printf("Use: %s < transactionlog\n", argv[0]); 67 | return retval; 68 | } 69 | 70 | while (1) { 71 | /* Read a request or reply from the transaction file */ 72 | doread(readfd, &magic, sizeof(magic)); 73 | magic = ntohl(magic); 74 | switch (magic) { 75 | case NBD_REQUEST_MAGIC: 76 | doread(readfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic)); 77 | cookie = ntohll(req.cookie); 78 | offset = ntohll(req.from); 79 | len = ntohl(req.len); 80 | command = ntohl(req.type); 81 | 82 | ctext = getcommandname(command & NBD_CMD_MASK_COMMAND); 83 | 84 | printf("> H=%016llx C=0x%08x (%20s+%4s) O=%016llx L=%08x\n", 85 | (long long unsigned int) cookie, 86 | command, 87 | ctext, 88 | (command & NBD_CMD_FLAG_FUA)?"FUA":"NONE", 89 | (long long unsigned int) offset, 90 | len); 91 | if (((command & NBD_CMD_MASK_COMMAND) == NBD_CMD_WRITE) && 92 | g_with_datalog) { 93 | while (len > 0) { 94 | uint32_t tmplen = len; 95 | 96 | if (tmplen > BUFSIZE) 97 | tmplen = BUFSIZE; 98 | doread(readfd, tmpbuf, tmplen); 99 | len -= tmplen; 100 | } 101 | } 102 | 103 | break; 104 | case NBD_REPLY_MAGIC: 105 | doread(readfd, sizeof(magic)+(char *)(&rep), sizeof(struct nbd_reply)-sizeof(magic)); 106 | cookie = ntohll(rep.cookie); 107 | error = ntohl(rep.error); 108 | 109 | printf("< H=%016llx E=0x%08x\n", 110 | (long long unsigned int) cookie, 111 | error); 112 | break; 113 | 114 | case NBD_TRACELOG_MAGIC: 115 | doread(readfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic)); 116 | cookie = ntohll(req.cookie); 117 | offset = ntohll(req.from); 118 | len = ntohl(req.len); 119 | command = ntohl(req.type); 120 | 121 | ctext = gettracelogname(command); 122 | 123 | printf("TRACE_OPTION C=0x%08x (%23s) O=%016llx L=%08x\n", 124 | command, 125 | ctext, 126 | (long long unsigned int) offset, 127 | len); 128 | if (offset == NBD_TRACELOG_FROM_MAGIC) { 129 | 130 | switch (command) { 131 | case NBD_TRACELOG_SET_DATALOG: 132 | g_with_datalog = !!len; 133 | printf("TRACE_OPTION DATALOG set to %d.\n", (int)g_with_datalog); 134 | break; 135 | default: 136 | printf("TRACE_OPTION ? Unknown type\n"); 137 | } 138 | } else { 139 | printf("TRACE_OPTION ? Unknown FROM_MAGIC\n"); 140 | } 141 | break; 142 | case NBD_STRUCTURED_REPLY_MAGIC: 143 | doread(readfd, sizeof(magic)+(char*)(&srep), sizeof(struct nbd_structured_reply)-sizeof(magic)); 144 | cookie = ntohll(srep.cookie); 145 | flags = ntohs(srep.flags); 146 | type = ntohs(srep.type); 147 | paylen = ntohs(srep.paylen); 148 | ctext = getstructreplname(type); 149 | 150 | printf(" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #if SIZEOF_UNSIGNED_SHORT_INT==4 20 | typedef unsigned short u32; 21 | #elif SIZEOF_UNSIGNED_INT==4 22 | typedef unsigned int u32; 23 | #elif SIZEOF_UNSIGNED_LONG_INT==4 24 | typedef unsigned long u32; 25 | #else 26 | #error I need at least some 32-bit type 27 | #endif 28 | 29 | #if SIZEOF_UNSIGNED_INT==8 30 | typedef unsigned int u64; 31 | #elif SIZEOF_UNSIGNED_LONG_INT==8 32 | typedef unsigned long u64; 33 | #elif SIZEOF_UNSIGNED_LONG_LONG_INT==8 34 | typedef unsigned long long u64; 35 | #else 36 | #error I need at least some 64-bit type 37 | #endif 38 | 39 | #define __be32 u32 40 | #define __be64 u64 41 | #include "nbd.h" 42 | 43 | #ifndef HAVE_FDATASYNC 44 | #define fdatasync(arg) fsync(arg) 45 | #endif 46 | 47 | #if NBD_LFS==1 48 | /* /usr/include/features.h (included from /usr/include/sys/types.h) 49 | defines this when _GNU_SOURCE is defined 50 | */ 51 | #ifndef _LARGEFILE_SOURCE 52 | #define _LARGEFILE_SOURCE 53 | #endif 54 | #define _FILE_OFFSET_BITS 64 55 | #endif 56 | 57 | #ifndef G_GNUC_NORETURN 58 | #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) 59 | #define G_GNUC_NORETURN __attribute__((__noreturn__)) 60 | #define G_GNUC_UNUSED __attribute__((unused)) 61 | #else 62 | #define G_GNUC_NORETURN 63 | #define G_GNUC_UNUSED 64 | #endif 65 | #endif 66 | 67 | extern const u64 cliserv_magic; 68 | extern const u64 opts_magic; 69 | extern const u64 rep_magic; 70 | 71 | #define INIT_PASSWD "NBDMAGIC" 72 | 73 | #define INFO(a) do { } while(0) 74 | 75 | int set_nonblocking(int fd, int nb); 76 | void setmysockopt(int sock); 77 | void err_nonfatal(const char *s); 78 | 79 | void nbd_err(const char *s) G_GNUC_NORETURN; 80 | void nbd_err_code(const char *s, int code) G_GNUC_NORETURN; 81 | #define err(S) nbd_err(S) 82 | #define err_code(S, C) nbd_err_code(S, C) 83 | 84 | void logging(const char* name); 85 | 86 | #ifndef ntohll 87 | uint64_t ntohll(uint64_t a); 88 | #endif 89 | #ifndef htonll 90 | #define htonll ntohll 91 | #endif 92 | 93 | int readit(int f, void *buf, size_t len); 94 | int writeit(int f, const void *buf, size_t len); 95 | 96 | #define NBD_DEFAULT_PORT "10809" /* Port on which named exports are 97 | * served */ 98 | 99 | /* Options that the client can select to the server */ 100 | #define NBD_OPT_EXPORT_NAME (1) /**< Client wants to select a named export (is followed by name of export) */ 101 | #define NBD_OPT_ABORT (2) /**< Client wishes to abort negotiation */ 102 | #define NBD_OPT_LIST (3) /**< Client request list of supported exports (not followed by data) */ 103 | #define NBD_OPT_STARTTLS (5) /**< Client wishes to initiate TLS */ 104 | #define NBD_OPT_INFO (6) /**< Client wants information about the given export */ 105 | #define NBD_OPT_GO (7) /**< Client wants to select the given and move to the transmission phase */ 106 | #define NBD_OPT_STRUCTURED_REPLY (8) /**< Client wants to see structured replies */ 107 | 108 | /* Replies the server can send during negotiation */ 109 | #define NBD_REP_ACK (1) /**< ACK a request. Data: option number to be acked */ 110 | #define NBD_REP_SERVER (2) /**< Reply to NBD_OPT_LIST (one of these per server; must be followed by NBD_REP_ACK to signal the end of the list */ 111 | #define NBD_REP_INFO (3) /**< Reply to NBD_OPT_INFO */ 112 | #define NBD_REP_FLAG_ERROR (1 << 31) /** If the high bit is set, the reply is an error */ 113 | #define NBD_REP_ERR_UNSUP (1 | NBD_REP_FLAG_ERROR) /**< Client requested an option not understood by this version of the server */ 114 | #define NBD_REP_ERR_POLICY (2 | NBD_REP_FLAG_ERROR) /**< Client requested an option not allowed by server configuration. (e.g., the option was disabled) */ 115 | #define NBD_REP_ERR_INVALID (3 | NBD_REP_FLAG_ERROR) /**< Client issued an invalid request */ 116 | #define NBD_REP_ERR_PLATFORM (4 | NBD_REP_FLAG_ERROR) /**< Option not supported on this platform */ 117 | #define NBD_REP_ERR_TLS_REQD (5 | NBD_REP_FLAG_ERROR) /**< TLS required */ 118 | #define NBD_REP_ERR_UNKNOWN (6 | NBD_REP_FLAG_ERROR) /**< NBD_OPT_INFO or ..._GO requested on unknown export */ 119 | #define NBD_REP_ERR_BLOCK_SIZE_REQD (8 | NBD_REP_FLAG_ERROR) /**< Server is not willing to serve the export without the block size being negotiated */ 120 | 121 | /* Global flags */ 122 | #define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) /**< new-style export that actually supports extending */ 123 | #define NBD_FLAG_NO_ZEROES (1 << 1) /**< we won't send the 128 bits of zeroes if the client sends NBD_FLAG_C_NO_ZEROES */ 124 | /* Flags from client to server. */ 125 | #define NBD_FLAG_C_FIXED_NEWSTYLE NBD_FLAG_FIXED_NEWSTYLE 126 | #define NBD_FLAG_C_NO_ZEROES NBD_FLAG_NO_ZEROES 127 | 128 | /* Info types */ 129 | #define NBD_INFO_EXPORT (0) 130 | #define NBD_INFO_NAME (1) 131 | #define NBD_INFO_DESCRIPTION (2) 132 | #define NBD_INFO_BLOCK_SIZE (3) 133 | -------------------------------------------------------------------------------- /man/nbd-trdump.1.sgml.in: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | --> 11 | 12 | 13 | Wouter"> 14 | Verhelst"> 15 | 16 | $Date$"> 17 | 19 | 1"> 20 | wouter@debian.org"> 21 | 22 | nbd-trdump"> 23 | 24 | 25 | Debian GNU/Linux"> 26 | GNU"> 27 | ]> 28 | 29 | 30 | 31 |
32 | &dhemail; 33 |
34 | 35 | &dhfirstname; 36 | &dhsurname; 37 | 38 | 39 | 2001 40 | &dhusername; 41 | 42 | &dhdate; 43 |
44 | 45 | &dhucpackage; 46 | 47 | &dhsection; 48 | 49 | 50 | &dhpackage; 51 | 52 | translate an nbd transaction log into human readable form 53 | 54 | 55 | 56 | &dhpackage; 57 | 58 | 59 | 60 | DESCRIPTION 61 | 62 | &dhpackage; translates 63 | a transaction log produced by nbd-server 64 | (specifically by the transactionlog 65 | configuration directive) into human readable form. 66 | 67 | The command acts as a traditional UNIX filter, i.e. the 68 | transaction log must be supplied on standard input, and the 69 | human readable output is sent to standard output. 70 | 71 | 72 | OUTPUT 73 | 74 | The following may be output: 75 | 76 | 77 | 78 | 79 | 80 | A request packet sent from the client to the server. 81 | 82 | 83 | 84 | 85 | 86 | A reply packet sent from the server to the client. 87 | 88 | 89 | 90 | 91 | 92 | A structured reply packet sent from the server to the client. 93 | 94 | 95 | 96 | 97 | 98 | The cookie of the packet. Note: previous versions of 99 | this man page (and the NBD spec) referred to the cookie as the 100 | "handle". 101 | 102 | 103 | 104 | 105 | 106 | The command sent. 107 | 108 | 109 | 110 | 111 | 112 | The offet from the start of the disk. 113 | 114 | 115 | 116 | 117 | 118 | The length of data. 119 | 120 | 121 | 122 | 123 | 124 | The error returned. 125 | 126 | 127 | 128 | 129 | 130 | The type of the structured reply message. 131 | 132 | 133 | 134 | 135 | 136 | The flags on the structured reply message. 137 | 138 | 139 | 140 | 141 | 142 | SEE ALSO 143 | 144 | nbd-server (1). 145 | 146 | 147 | 148 | AUTHOR 149 | The NBD kernel module and the NBD tools have been written by 150 | Pavel Macheck (pavel@ucw.cz). 151 | 152 | The kernel module is now maintained by Paul Clements 153 | (Paul.Clements@steeleye.com), while the userland tools are maintained by 154 | Wouter Verhelst (wouter@debian.org) 155 | 156 | This manual page was written by &dhusername; (&dhemail;) for 157 | the &debian; system (but may be used by others). Permission is 158 | granted to copy, distribute and/or modify this document under the 159 | terms of the GNU General Public License, 160 | version 2, as published by the Free Software Foundation. 161 | 162 | 163 |
164 | -------------------------------------------------------------------------------- /buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 Wrymouth Innovation Ltd 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | #include 28 | 29 | #include "buffer.h" 30 | 31 | struct buffer 32 | { 33 | char *buf; 34 | ssize_t size; 35 | ssize_t hwm; 36 | ssize_t ridx; 37 | ssize_t widx; 38 | int empty; 39 | }; 40 | 41 | /* the buffer is organised internally as follows: 42 | * 43 | * * There are b->size bytes in the buffer. 44 | * 45 | * * Bytes are at offsets 0 to b->size-1 46 | * 47 | * * b->ridx points to the first readable byte 48 | * 49 | * * b->widx points to the first empty space 50 | * 51 | * * b->ridx < b->widx indicates a non-wrapped buffer: 52 | * 53 | * 0 ridx widx size 54 | * | | | | 55 | * V V V V 56 | * ........XXXXXXXXX................ 57 | * 58 | * * b->ridx > b->widx indicates a wrapped buffer: 59 | * 60 | * 0 widx ridx size 61 | * | | | | 62 | * V V V V 63 | * XXXXXXXX.........XXXXXXXXXXXXXXXX 64 | * 65 | * * b->ridx == b->widx indicates a FULL buffer: 66 | * 67 | * * b->ridx == b->widx indicates a wrapped buffer: 68 | * 69 | * 0 widx == ridx size 70 | * | | | 71 | * V V V 72 | * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 73 | * 74 | * An empty buffer is indicated by empty=1 75 | * 76 | */ 77 | 78 | buffer_t * 79 | bufNew (ssize_t size, ssize_t hwm) 80 | { 81 | buffer_t *b = calloc (1, sizeof (buffer_t)); 82 | b->buf = calloc (1, size); 83 | b->size = size; 84 | b->hwm = hwm; 85 | b->empty = 1; 86 | return b; 87 | } 88 | 89 | 90 | void 91 | bufFree (buffer_t * b) 92 | { 93 | free (b->buf); 94 | free (b); 95 | } 96 | 97 | /* get a maximal span to read. Returns 0 if buffer 98 | * is empty 99 | */ 100 | ssize_t 101 | bufGetReadSpan (buffer_t * b, void **addr) 102 | { 103 | if (b->empty) 104 | { 105 | *addr = NULL; 106 | return 0; 107 | } 108 | *addr = &(b->buf[b->ridx]); 109 | ssize_t len = b->widx - b->ridx; 110 | if (len <= 0) 111 | len = b->size - b->ridx; 112 | return len; 113 | } 114 | 115 | /* get a maximal span to write. Returns 0 id buffer is full 116 | */ 117 | ssize_t 118 | bufGetWriteSpan (buffer_t * b, void **addr) 119 | { 120 | if (b->empty) 121 | { 122 | *addr = b->buf; 123 | b->ridx = 0; 124 | b->widx = 0; 125 | return b->size; 126 | } 127 | if (b->ridx == b->widx) 128 | { 129 | *addr = NULL; 130 | return 0; 131 | } 132 | *addr = &(b->buf[b->widx]); 133 | ssize_t len = b->ridx - b->widx; 134 | if (len <= 0) 135 | len = b->size - b->widx; 136 | return len; 137 | } 138 | 139 | /* mark size bytes as read */ 140 | void 141 | bufDoneRead (buffer_t * b, ssize_t size) 142 | { 143 | while (!b->empty && (size > 0)) 144 | { 145 | /* empty can't occur here, so equal pointers means full */ 146 | ssize_t len = b->widx - b->ridx; 147 | if (len <= 0) 148 | len = b->size - b->ridx; 149 | 150 | /* len is the number of bytes in one read span */ 151 | if (len > size) 152 | len = size; 153 | 154 | b->ridx += len; 155 | if (b->ridx >= b->size) 156 | b->ridx = 0; 157 | 158 | if (b->ridx == b->widx) 159 | { 160 | b->ridx = 0; 161 | b->widx = 0; 162 | b->empty = 1; 163 | } 164 | 165 | size -= len; 166 | } 167 | } 168 | 169 | /* mark size bytes as written */ 170 | void 171 | bufDoneWrite (buffer_t * b, ssize_t size) 172 | { 173 | while ((b->empty || (b->ridx != b->widx)) && (size > 0)) 174 | { 175 | /* full can't occur here, so equal pointers means empty */ 176 | ssize_t len = b->ridx - b->widx; 177 | if (len <= 0) 178 | len = b->size - b->widx; 179 | 180 | /* len is the number of bytes in one write span */ 181 | if (len > size) 182 | len = size; 183 | 184 | b->widx += len; 185 | if (b->widx >= b->size) 186 | b->widx = 0; 187 | 188 | /* it can't be empty as we've written at least one byte */ 189 | b->empty = 0; 190 | 191 | size -= len; 192 | } 193 | } 194 | 195 | int 196 | bufIsEmpty (buffer_t * b) 197 | { 198 | return b->empty; 199 | } 200 | 201 | int 202 | bufIsFull (buffer_t * b) 203 | { 204 | return !b->empty && (b->ridx == b->widx); 205 | } 206 | 207 | int 208 | bufIsOverHWM (buffer_t * b) 209 | { 210 | return bufGetCount (b) > b->hwm; 211 | } 212 | 213 | ssize_t 214 | bufGetFree (buffer_t * b) 215 | { 216 | return b->size - bufGetCount (b); 217 | } 218 | 219 | ssize_t 220 | bufGetCount (buffer_t * b) 221 | { 222 | if (b->empty) 223 | return 0; 224 | return b->widx - b->ridx + ((b->ridx < b->widx) ? 0 : b->size); 225 | } 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NBD README 2 | ========== 3 | 4 | Welcome to the NBD userland support files! 5 | 6 | This package contains nbd-server and nbd-client. 7 | 8 | To install the package, download the source and do the normal 9 | `configure`/`make`/`make install` dance. You'll need to install it on both the 10 | client and the server. 11 | 12 | For compiling from git, do a checkout, install the SGML tools 13 | (docbook2man), and then run './autogen.sh' while inside your checkout. 14 | Then, see above. 15 | 16 | Contributing 17 | ------------ 18 | 19 | If you want to send a patch, please do not open a pull request; instead, send 20 | it to the 21 | [mailinglist](https://lists.debian.org/nbd) 22 | 23 | Security issues 24 | --------------- 25 | 26 | If you think you found a security problem in NBD, please contact the 27 | mailinglist. Do *not* just file an issue for this (although you may do 28 | so too if you prefer). 29 | 30 | For embargoed issues, please contact Wouter Verhelst 31 | 32 | Using NBD 33 | --------- 34 | 35 | NBD is quite easy to use. First, on the client, you need to load the module 36 | and, if you're not using udev, to create the device nodes: 37 | 38 | # modprobe nbd 39 | # cd /dev 40 | # ./MAKEDEV nbd0 41 | 42 | (if you need more than one NBD device, repeat the above command for nbd1, 43 | nbd2, ...) 44 | 45 | Next, write a configuration file for the server. An example looks like 46 | this: 47 | 48 | # This is a comment 49 | [generic] 50 | # The [generic] section is required, even if nothing is specified 51 | # there. 52 | # When either of these options are specified, nbd-server drops 53 | # privileges to the given user and group after opening ports, but 54 | # _before_ opening files. 55 | user = nbd 56 | group = nbd 57 | [export1] 58 | exportname = /export/nbd/export1-file 59 | authfile = /export/nbd/export1-authfile 60 | timeout = 30 61 | filesize = 10000000 62 | readonly = false 63 | multifile = false 64 | copyonwrite = false 65 | prerun = dd if=/dev/zero of=%s bs=1k count=500 66 | postrun = rm -f %s 67 | [otherexport] 68 | exportname = /export/nbd/experiment 69 | # The other options are all optional 70 | 71 | The configuration file is parsed with GLib's GKeyFile, which parses key 72 | files as they are specified in the Freedesktop.org Desktop Entry 73 | Specification, as can be found at 74 | . While this format 75 | was not intended to be used for configuration files, the glib API is 76 | flexible enough for it to be used as such. 77 | 78 | Now start the server: 79 | 80 | nbd-server -C /path/to/configfile 81 | 82 | Note that the filename must be an absolute path; i.e., something like 83 | `/path/to/file`, not `../file`. See the nbd-server manpage for details 84 | on any available options. 85 | 86 | Finally, you'll be able to start the client: 87 | 88 | nbd-client -N 89 | 90 | e.g., 91 | 92 | nbd-client 10.0.0.1 -N otherexport /dev/nbd0 93 | 94 | will use the second export in the above example (the one that exports 95 | `/export/nbd/experiment`) 96 | 97 | `nbd-client` must be ran as root; the same is not true for nbd-server 98 | (but do make sure that /var/run is writeable by the server that 99 | `nbd-server` runs as; otherwise, you won't get a PID file, though the 100 | server will keep running). 101 | 102 | There are packages (or similar) available for most current operating 103 | systems; see the "Packaging status" badge below for details. 104 | 105 | For questions, please use the [nbd@other.debian.org](mailto:nbd@other.debian.org) mailinglist. 106 | 107 | Alternate implementations 108 | ========================= 109 | 110 | Besides this project, the NBD protocol has been implemented by various 111 | other people. A (probably incomplete) list follows: 112 | 113 | * [nbdkit](https://gitlab.com/nbdkit/nbdkit) is a multithreaded NBD 114 | server with a plugin architecture. 115 | * [libnbd](https://gitlab.com/nbdkit/libnbd) is a library to aid in 116 | writing NBD clients 117 | * [qemu](https://www.qemu.org) contains an embedded NBD server, an 118 | embedded NBD client, and a standalone NBD server (`qemu-nbd`). They 119 | maintain a [status 120 | document](https://gitlab.com/qemu-project/qemu/-/blob/master/docs/interop/nbd.rst) 121 | of their NBD implementation. 122 | * A [GEOM gate-based client implementation for 123 | FreeBSD](https://github.com/freqlabs/nbd-client) exists. It has not 124 | seen any updates since 2018, and only implements the client side 125 | (any server should run on FreeBSD unmodified, however). 126 | * A Windows client implementation exists as part of the [RBD 127 | implementation](https://docs.ceph.com/en/latest/rbd/rbd-windows/) of 128 | [Ceph for Windows](https://cloudbase.it/ceph-for-windows/). 129 | * [lwNBD](https://github.com/bignaux/lwNBD) is a NBD server library, 130 | targetting bare metal or OS embedded system. It has a plugin architecture. 131 | 132 | Additionally, these implementations once existed but are now no longer 133 | maintained: 134 | 135 | * xnbd: This was an NBD implementation with a few extra protocol 136 | messages that allowed for live migration. Its code repository has 137 | disappeared. 138 | * enbd: This was an NBD implementation with a few extra protocol 139 | messages that allowed extra ioctl calls to be passed on (e.g., the 140 | "eject" message for a CD-ROM device that was being exported through 141 | NBD). It appears to no longer be maintained. 142 | * Hurd translator: There was a [proof-of-concept 143 | implementation](https://lists.debian.org/debian-hurd/2001/09/msg00174.html) 144 | of the NBD protocol once as a translator for The Hurd. We do not know 145 | what its current status is. 146 | * Christoph Lohmann once wrote a client implementation for Plan 9. The 147 | link he provided us is now stale; we do not know what its current 148 | status is. 149 | 150 | Badges 151 | ====== 152 | 153 | [![Download Network Block Device](https://img.shields.io/sourceforge/dm/nbd.svg)](https://sourceforge.net/projects/nbd/files/latest/download) 154 | [![Coverity Scan Build Status](https://scan.coverity.com/projects/1243/badge.svg)](https://scan.coverity.com/projects/1243) 155 | [![CII badge](https://bestpractices.coreinfrastructure.org/projects/281/badge)](https://bestpractices.coreinfrastructure.org/projects/281) 156 | [![Travis](https://img.shields.io/travis/NetworkBlockDevice/nbd.svg)](https://travis-ci.org/NetworkBlockDevice/nbd) 157 | 158 | [![Packaging status](https://repology.org/badge/vertical-allrepos/nbd.svg)](https://repology.org/metapackage/nbd) 159 | -------------------------------------------------------------------------------- /doc/uri.md: -------------------------------------------------------------------------------- 1 | # The NBD Uniform Resource Indicator (URI) format 2 | 3 | ## Introduction 4 | 5 | This document describes the standard URI format that clients may use 6 | to refer to an export located on an NBD server. 7 | 8 | ## Convention 9 | 10 | "NBD" stands for Network Block Device and refers to the protocol 11 | described in the adjacent protocol document also available online at 12 | 13 | 14 | "URI" stands for Uniform Resource Indicator and refers to the standard 15 | introduced in [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt) and 16 | subsequent IETF standards. 17 | 18 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", 19 | "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", 20 | "MAY", and "OPTIONAL" in this document are to be interpreted as 21 | described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). 22 | The same words in lower case carry their natural meaning. 23 | 24 | ## Related standards 25 | 26 | All NBD URIs MUST also be valid URIs as described in 27 | [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt) and any subsequent 28 | IETF standards describing URIs. This means that any parsing, quoting 29 | or encoding issues that may arise when making or parsing an NBD URI 30 | must be answered by consulting IETF standards. 31 | 32 | This standard defers any question about how the NBD protocol works to 33 | the NBD protocol document available online at 34 | 35 | 36 | ## NBD URI components 37 | 38 | An NBD URI consists of the following components: 39 | 40 | +------- Scheme (required) 41 | | 42 | | +------- Authority (optional) 43 | | | 44 | | | +------- Export name (optional) 45 | | | | 46 | v v v 47 | nbd://example.com:10809/export 48 | 49 | nbd+unix:///export?socket=nbd.sock 50 | ^ 51 | | 52 | +---- Query parameters 53 | 54 | ## NBD URI scheme 55 | 56 | One of the following scheme names SHOULD be used to indicate an NBD URI: 57 | 58 | * `nbd`: NBD over an unencrypted or opportunistically TLS encrypted 59 | TCP/IP connection. 60 | 61 | * `nbds`: NBD over a TLS encrypted TCP/IP connection. If encryption 62 | cannot be negotiated then the connection MUST fail. 63 | 64 | * `nbd+unix`: NBD over a Unix domain socket. The query parameters 65 | MUST include a parameter called `socket` which refers to the name of 66 | the Unix domain socket. 67 | 68 | * `nbds+unix`: NBD over a TLS encrypted Unix domain socket. If 69 | encryption cannot be negotiated then the connection MUST fail. The 70 | query parameters MUST include a parameter called `socket` which 71 | refers to the name of the Unix domain socket. 72 | 73 | Other URI scheme names MAY be used but not all NBD clients will 74 | understand them or even recognize that they refer to NBD. 75 | 76 | Note that using opportunistically encrypted connections (via the `nbd` 77 | or `nbd+unix` scheme) risks a protocol downgrade attack; whereas 78 | requests for a secure connection (via the `nbds` or `nbds+unix` 79 | scheme) MUST use TLS to connect. For more details, see 80 | 81 | 82 | ## NBD URI authority 83 | 84 | The authority field SHOULD be used for TCP/IP connections and SHOULD 85 | NOT be used for Unix domain socket connections. 86 | 87 | The authority field MAY contain the `userinfo`, `host` and/or `port` 88 | fields as defined in [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt) 89 | section 3.2. 90 | 91 | The `host` field may be a host name or IP address. Literal IPv6 92 | addresses MUST be formatted in the way specified by 93 | [RFC 2732](https://www.ietf.org/rfc/rfc2732.txt). 94 | 95 | If the `port` field is not present then it MUST default to the NBD 96 | port number assigned by IANA (10809). 97 | 98 | The `userinfo` field is used to supply a username for certain less 99 | common sorts of TLS authentication. If the `userinfo` field is not 100 | present but is needed by the client for TLS authentication then it 101 | SHOULD default to a local operating system credential if one is 102 | available. 103 | 104 | It is up to the NBD client what should happen if the authority field 105 | is not present for TCP/IP connections, or present for Unix domain 106 | socket connections. Options might include failing with an error, 107 | ignoring it, or using defaults. 108 | 109 | ## NBD URI export name 110 | 111 | If the version of the NBD protocol in use needs an export name, then 112 | the path part of the URI except for the leading `/` character MUST be 113 | passed to the server as the export name. 114 | 115 | For example: 116 | 117 | NBD URI Export name 118 | ---------------------------------------------------- 119 | nbd://example.com/disk disk 120 | nbd+unix:///disk?socket=sock disk 121 | nbd://example.com/ (empty string) 122 | nbd://example.com (empty string) 123 | nbd://example.com//disk /disk 124 | nbd://example.com/hello%20world hello world 125 | 126 | Note that export names are not usually paths, they are free text 127 | strings. In particular they do not usually start with a `/` 128 | character, they may be an empty string, and they may contain any 129 | Unicode character except NUL. 130 | 131 | ## NBD URI socket parameter 132 | 133 | If the scheme name indicates a Unix domain socket then the query 134 | parameters MUST include a `socket` key, referring to the Unix domain 135 | socket which on Unix-like systems is usually a special file on the 136 | local disk. 137 | 138 | On platforms which support Unix domain sockets in the abstract 139 | namespace, and if the client supports this, the `socket` parameter MAY 140 | begin with an ASCII NUL character. When the URI is properly encoded 141 | it will look like this: 142 | 143 | nbd+unix:///?socket=%00/abstract 144 | 145 | ## NBD URI query parameters related to TLS 146 | 147 | If TLS encryption is to be negotiated then the following query 148 | parameters MAY be present: 149 | 150 | * `tls-type`: Possible values include `anon`, `x509` or `psk`. This 151 | specifies the desired TLS authentication method. 152 | 153 | * `tls-hostname`: The optional TLS hostname to use for certificate 154 | verification. This can be used when connecting over a Unix domain 155 | socket since there is no hostname available in the URI authority 156 | field; or when DNS does not properly resolve the server's hostname. 157 | 158 | * `tls-verify-peer`: This optional parameter may be `0` or `1` to 159 | control whether the client verifies the server's identity. By 160 | default clients SHOULD verify the server's identity if TLS is 161 | negotiated and if a suitable Certificate Authority is available. 162 | 163 | ## Other NBD URI query parameters 164 | 165 | Clients SHOULD prefix experimental query parameters using `x-`. This 166 | SHOULD NOT be used for query parameters which are expected to be 167 | widely used. 168 | 169 | Any other query parameters which the client does not understand SHOULD 170 | be diagnosed by the parser. 171 | 172 | ## Clients which do not support TLS 173 | 174 | Wherever this document refers to encryption, authentication and TLS, 175 | clients which do not support TLS SHOULD give an error when 176 | encountering an NBD URI that requires TLS (such as one with a scheme 177 | name `nbds` or `nbds+unix`). 178 | -------------------------------------------------------------------------------- /tests/run/simple_test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Yes, that's POSIX sh, not bash! 3 | 4 | if [ -z "$TMPDIR" ] 5 | then 6 | TMPDIR=/tmp 7 | fi 8 | 9 | REALPATH=$(which realpath) 10 | if [ -z "$REALPATH" ] 11 | then 12 | REALPATH="readlink -f" 13 | fi 14 | 15 | tmpdir=`mktemp -d $TMPDIR/tmp.XXXXXX` 16 | conffile=${tmpdir}/nbd.conf 17 | pidfile=${tmpdir}/nbd.pid 18 | tmpnam=${tmpdir}/nbd.dd 19 | mydir=$(dirname $0) 20 | certdir=$($REALPATH ${mydir}/certs) 21 | cleanup="$2" 22 | PID="" 23 | DELAY=${DELAY:-1} 24 | 25 | set -e 26 | 27 | cleanup() { 28 | if [ -f ${pidfile} ] 29 | then 30 | kill `cat ${pidfile}` || true 31 | else 32 | if [ ! -z "$PID" ] 33 | then 34 | kill $PID || true 35 | fi 36 | fi 37 | if [ -z "$cleanup" ] 38 | then 39 | rm -rf $tmpdir 40 | else 41 | echo "Setup in $tmpdir" 42 | fi 43 | } 44 | 45 | abort() { 46 | cleanup 47 | trap - INT 48 | kill -INT $$ 49 | } 50 | 51 | trap -- cleanup EXIT 52 | trap -- abort INT 53 | 54 | # Create a one-meg device 55 | dd if=/dev/zero of=$tmpnam bs=1024 count=4096 >/dev/null 2>&1 56 | 57 | echo $1 58 | 59 | case $1 in 60 | */cfgsize) 61 | # Test oversized requests 62 | cat > ${conffile} < ${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <$tmpdir/confdir/exp1.conf <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} <${conffile} < 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "config.h" 22 | /* We don't want to do syslog output in this program */ 23 | #undef ISSERVER 24 | #include "cliserv.h" 25 | #include "nbd.h" 26 | #include "nbd-helper.h" 27 | 28 | #define BUFSIZE 131072 29 | static char g_tmpbuf[BUFSIZE]; 30 | 31 | static bool g_with_datalog = false; 32 | 33 | #define VERBOSE_DEBUG 3 34 | #define VERBOSE_DETAILS 2 35 | #define VERBOSE_NORMAL 1 36 | #define VERBOSE_OFF 0 37 | 38 | int g_verbose = 0; 39 | 40 | unsigned long g_blocksize = 512; 41 | unsigned long long g_cur_blocks = 0; 42 | unsigned long long g_max_blocks = ULLONG_MAX; 43 | 44 | static inline void doread(int f, char *buf, size_t len) { 45 | ssize_t res; 46 | 47 | while(len>0) { 48 | if((res=read(f, buf, len)) <=0) { 49 | if (!res) { 50 | /* normal exit, end of transaction log. */ 51 | printf("End of transaction log, total %llu blocks written.\n", 52 | (unsigned long long) g_cur_blocks); 53 | exit(0); 54 | } 55 | perror ("Error reading transactions"); 56 | exit(1); 57 | } 58 | len-=res; 59 | buf+=res; 60 | } 61 | } 62 | 63 | static inline void dowriteimage(int imagefd, const char *buf, size_t len, off_t offset) { 64 | ssize_t res; 65 | 66 | if (g_verbose >= VERBOSE_DETAILS) { 67 | printf("block %llu (0x%llx): writing to offset %lld (0x%llx), len %lld (0x%llx).\n", 68 | g_cur_blocks, g_cur_blocks, 69 | (long long)offset, (long long) offset, 70 | (long long) len, (long long) len); 71 | } 72 | 73 | while(len>0) { 74 | if((res=pwrite(imagefd, buf, len, offset)) <=0) { 75 | if (!res) 76 | exit(0); 77 | perror ("Error writing to image file"); 78 | exit(1); 79 | } 80 | len-=res; 81 | buf+=res; 82 | offset+=res; 83 | } 84 | } 85 | 86 | 87 | void process_command(uint32_t command, uint64_t offset, uint32_t len, int logfd, int imagefd) 88 | { 89 | if (offset % g_blocksize != 0) { 90 | printf(" Got offset %llu (0x%llx), not a multiple of the block size %ld (0x%lx).\n", 91 | (unsigned long long)offset, (unsigned long long)offset, g_blocksize, g_blocksize); 92 | exit(1); 93 | } 94 | if (len % g_blocksize != 0) { 95 | printf(" Got len %lu (0x%lx), not a multiple of the block size %ld (0x%lx).\n", 96 | (unsigned long) len, (unsigned long) len, g_blocksize, g_blocksize); 97 | exit(1); 98 | } 99 | 100 | switch (command & NBD_CMD_MASK_COMMAND) { 101 | case NBD_CMD_READ: 102 | case NBD_CMD_DISC: 103 | case NBD_CMD_FLUSH: 104 | /* READ, DISCONNECT, FLUSH: nothing to do */ 105 | break; 106 | case NBD_CMD_WRITE: 107 | if (!g_with_datalog) { 108 | printf(" NBD_CMD_WRITE without data log, replay impossible.\n"); 109 | exit(1); 110 | } 111 | while (len > 0) { 112 | doread(logfd, g_tmpbuf, g_blocksize); 113 | dowriteimage(imagefd, g_tmpbuf, g_blocksize, offset); 114 | 115 | offset+=g_blocksize; 116 | len-=g_blocksize; 117 | g_cur_blocks++; 118 | 119 | if (g_cur_blocks == g_max_blocks) { 120 | printf("g_max_blocks (%llu, 0x%llx) reached!.\n", g_max_blocks, g_max_blocks); 121 | exit(0); 122 | } 123 | } 124 | break; 125 | case NBD_CMD_TRIM: 126 | case NBD_CMD_WRITE_ZEROES: 127 | while (len > 0) { 128 | memset(g_tmpbuf, 0, g_blocksize); 129 | dowriteimage(imagefd, g_tmpbuf, g_blocksize, offset); 130 | 131 | offset+=g_blocksize; 132 | len-=g_blocksize; 133 | g_cur_blocks++; 134 | 135 | if (g_cur_blocks == g_max_blocks) { 136 | printf("g_max_blocks (%llu, 0x%llx) reached!.\n", g_max_blocks, g_max_blocks); 137 | exit(0); 138 | } 139 | } 140 | break; 141 | default: 142 | printf(" Unexpected command %d (0x%x), replay impossible.\n", 143 | (unsigned int) command, (unsigned int) command); 144 | exit(1); 145 | } 146 | } 147 | 148 | int main_loop(int logfd, int imagefd) { 149 | struct nbd_request req; 150 | struct nbd_reply rep; 151 | uint32_t magic; 152 | uint64_t cookie; 153 | uint32_t error; 154 | uint32_t command; 155 | uint32_t len; 156 | uint64_t offset; 157 | const char * ctext; 158 | 159 | while (1) { 160 | /* Read a request or reply from the transaction file */ 161 | doread(logfd, (char*) &magic, sizeof(magic)); 162 | magic = ntohl(magic); 163 | switch (magic) { 164 | case NBD_REQUEST_MAGIC: 165 | doread(logfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic)); 166 | cookie = ntohll(req.cookie); 167 | offset = ntohll(req.from); 168 | len = ntohl(req.len); 169 | command = ntohl(req.type); 170 | 171 | ctext = getcommandname(command & NBD_CMD_MASK_COMMAND); 172 | 173 | if (g_verbose >= VERBOSE_NORMAL) { 174 | printf("> H=%016llx C=0x%08x (%13s+%4s) O=%016llx L=%08x\n", 175 | (long long unsigned int) cookie, 176 | command, 177 | ctext, 178 | (command & NBD_CMD_FLAG_FUA)?"FUA":"NONE", 179 | (long long unsigned int) offset, 180 | len); 181 | } 182 | process_command(command, offset, len, logfd, imagefd); 183 | 184 | break; 185 | 186 | case NBD_REPLY_MAGIC: 187 | doread(logfd, sizeof(magic)+(char *)(&rep), sizeof(struct nbd_reply)-sizeof(magic)); 188 | cookie = ntohll(rep.cookie); 189 | error = ntohl(rep.error); 190 | 191 | if (g_verbose >= VERBOSE_NORMAL) { 192 | printf("< H=%016llx E=0x%08x\n", 193 | (long long unsigned int) cookie, 194 | error); 195 | } 196 | break; 197 | 198 | case NBD_TRACELOG_MAGIC: 199 | doread(logfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic)); 200 | cookie = ntohll(req.cookie); 201 | offset = ntohll(req.from); 202 | len = ntohl(req.len); 203 | command = ntohl(req.type); 204 | 205 | ctext = gettracelogname(command); 206 | 207 | if (g_verbose >= VERBOSE_NORMAL) { 208 | printf("TRACE_OPTION C=0x%08x (%23s) O=%016llx L=%08x\n", 209 | command, 210 | ctext, 211 | (long long unsigned int) offset, 212 | len); 213 | } 214 | if (offset == NBD_TRACELOG_FROM_MAGIC) { 215 | 216 | switch (command) { 217 | case NBD_TRACELOG_SET_DATALOG: 218 | g_with_datalog = !!len; 219 | if (g_verbose >= VERBOSE_NORMAL) 220 | printf("TRACE_OPTION DATALOG set to %d.\n", (int)g_with_datalog); 221 | break; 222 | default: 223 | printf("TRACE_OPTION ? Unknown type\n"); 224 | } 225 | } else { 226 | printf("TRACE_OPTION ? Unknown FROM_MAGIC\n"); 227 | } 228 | break; 229 | 230 | 231 | default: 232 | printf("? Unknown transaction type %08x, replay impossible.\n", magic); 233 | exit(1); 234 | } 235 | 236 | } 237 | /* never reached */ 238 | return 0; 239 | } 240 | 241 | static void show_help(const char *progname) { 242 | printf("\n"); 243 | printf("This is nbd-trplay, part of nbd %s.\n", PACKAGE_VERSION); 244 | printf("Use: %s -i -l [-m ] [-b elements from file to disk image .\n"); 246 | printf(" Command line parameters:\n"); 247 | printf(" : name of the initial image file.\n"); 248 | printf(" : nbd trace log. Must contain actual data (datalog=true).\n"); 249 | printf(" : device block size. Default 512.\n"); 250 | printf(" : where to stop the replay. Default all.\n"); 251 | printf(" -v: Increase verbose level. Specify multiple times to increase further.\n"); 252 | 253 | } 254 | 255 | 256 | int main(int argc, char **argv) { 257 | int opt; 258 | int imagefd = -1; 259 | int logfd = -1; 260 | 261 | printf("%s -i -l [-m ] [-b = VERBOSE_DEBUG) { 265 | printf("getopt: opt %c, optarg %s.\n", (char)opt, optarg); 266 | } 267 | switch(opt) { 268 | case 'v': 269 | g_verbose++; 270 | break; 271 | default: 272 | case '?': 273 | case 'h': 274 | show_help(argv[0]); 275 | return 0; 276 | case 'm': 277 | g_max_blocks = strtoull(optarg, NULL, 0); 278 | if (g_max_blocks == 0) { 279 | printf(" Invalid block count.\n"); 280 | return 1; 281 | } 282 | break; 283 | case 'b': 284 | g_blocksize = strtoul(optarg, NULL, 0); 285 | if (g_blocksize == 0) { 286 | printf(" Invalid block size.\n"); 287 | return 1; 288 | } 289 | if (g_blocksize > BUFSIZE) { 290 | printf(" block size is larger than %d, not supported.\n", (int)BUFSIZE); 291 | return 1; 292 | } 293 | break; 294 | case 'i': 295 | imagefd = open(optarg, O_RDWR, 0); 296 | if (imagefd == -1) { 297 | printf(" Opening disk image failed, errno %d.", errno); 298 | return 1; 299 | } 300 | break; 301 | case 'l': 302 | logfd = open(optarg, O_RDONLY, 0); 303 | if (logfd == -1) { 304 | printf(" Opening disk image failed, errno %d.", errno); 305 | return 1; 306 | } 307 | break; 308 | } 309 | } 310 | 311 | if (logfd == -1) { 312 | printf(" Log file not specified, this is mandatory.\n"); 313 | return 1; 314 | } 315 | if (imagefd == -1) { 316 | printf(" Disk image not specified, this is mandatory.\n"); 317 | return 1; 318 | } 319 | 320 | if (g_verbose >= VERBOSE_NORMAL) { 321 | printf(" block size: %ld bytes (0x%lx bytes).\n", g_blocksize, g_blocksize); 322 | printf(" max blocks to apply: %llu (0x%llx).\n", g_max_blocks, g_max_blocks); 323 | } 324 | main_loop(logfd, imagefd); 325 | 326 | return 0; 327 | } 328 | -------------------------------------------------------------------------------- /nbdsrv.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "nbd-debug.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "backend.h" 21 | #ifdef HAVE_SYS_IOCTL_H 22 | #include 23 | #endif 24 | #ifdef HAVE_SYS_MOUNT_H 25 | #include 26 | #endif 27 | 28 | #define LINELEN 256 /**< Size of static buffer used to read the 29 | authorization file (yuck) */ 30 | #include 31 | 32 | bool address_matches(const char* mask, const struct sockaddr* addr, GError** err) { 33 | struct addrinfo *res, *aitmp, hints; 34 | char *masksep; 35 | char privmask[strlen(mask)+1]; 36 | int masklen; 37 | int addrlen = addr->sa_family == AF_INET ? 4 : 16; 38 | #define IPV4_MAP_PREFIX 12 39 | uint8_t ipv4_mapped[IPV4_MAP_PREFIX+4] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 255, 255, 0, 0, 0, 0}; 41 | 42 | strcpy(privmask, mask); 43 | 44 | memset(&hints, 0, sizeof(hints)); 45 | hints.ai_family = AF_UNSPEC; 46 | hints.ai_flags = AI_NUMERICHOST; 47 | 48 | if((masksep = strchr(privmask, '/'))) { 49 | *masksep = '\0'; 50 | masklen = strtol(++masksep, NULL, 10); 51 | } else { 52 | masklen = addrlen * 8; 53 | } 54 | 55 | if (masklen > addrlen * 8 || masklen < 0) { 56 | g_set_error(err, NBDS_ERR, NBDS_ERR_CFILE_VALUE_INVALID, "could not parse netmask line: invalid mask length"); 57 | return false; 58 | } 59 | 60 | int e; 61 | if((e = getaddrinfo(privmask, NULL, &hints, &res))) { 62 | g_set_error(err, NBDS_ERR, NBDS_ERR_GAI, "could not parse netmask line: %s", gai_strerror(e)); 63 | return false; 64 | } 65 | aitmp = res; 66 | while(res) { 67 | assert(addr->sa_family == AF_INET || addr->sa_family == AF_INET6); 68 | const uint8_t* byte_s; 69 | uint8_t* byte_t; 70 | uint8_t mask = 0; 71 | int len_left = masklen; 72 | if(res->ai_family == addr->sa_family) { 73 | /* Both addresses are the same address family so do a simple comparison */ 74 | switch(addr->sa_family) { 75 | case AF_INET: 76 | byte_s = (const uint8_t*)(&(((struct sockaddr_in*)addr)->sin_addr)); 77 | byte_t = (uint8_t*)(&(((struct sockaddr_in*)(res->ai_addr))->sin_addr)); 78 | break; 79 | case AF_INET6: 80 | byte_s = (const uint8_t*)(&(((struct sockaddr_in6*)addr)->sin6_addr)); 81 | byte_t = (uint8_t*)(&(((struct sockaddr_in6*)(res->ai_addr))->sin6_addr)); 82 | break; 83 | } 84 | } else { 85 | /* Addresses are different families, compare IPv4-mapped IPv6 address */ 86 | switch(addr->sa_family) { 87 | case AF_INET: 88 | /* Map client address to IPv6 for comparison */ 89 | memcpy(&ipv4_mapped[IPV4_MAP_PREFIX], &(((struct sockaddr_in*)addr)->sin_addr), 4); 90 | byte_s = (const uint8_t*)&ipv4_mapped; 91 | byte_t = (uint8_t*)(&(((struct sockaddr_in6*)(res->ai_addr))->sin6_addr)); 92 | len_left += IPV4_MAP_PREFIX * 8; 93 | break; 94 | case AF_INET6: 95 | byte_s = (const uint8_t*)(&(((struct sockaddr_in6*)addr)->sin6_addr)); 96 | /* Map res to IPv6 for comparison */ 97 | memcpy(&ipv4_mapped[IPV4_MAP_PREFIX], &(((struct sockaddr_in*)(res->ai_addr))->sin_addr), 4); 98 | byte_t = &ipv4_mapped[0]; 99 | len_left += IPV4_MAP_PREFIX * 8; 100 | break; 101 | } 102 | } 103 | while(len_left >= 8) { 104 | if(*byte_s != *byte_t) { 105 | goto next; 106 | } 107 | byte_s++; byte_t++; 108 | len_left -= 8; 109 | } 110 | if(len_left) { 111 | mask = getmaskbyte(len_left); 112 | if((*byte_s & mask) != (*byte_t & mask)) { 113 | goto next; 114 | } 115 | } 116 | freeaddrinfo(aitmp); 117 | return true; 118 | next: 119 | res = res->ai_next; 120 | } 121 | freeaddrinfo(aitmp); 122 | return false; 123 | } 124 | 125 | uint8_t getmaskbyte(int masklen) { 126 | if(masklen >= 8) { 127 | return 0xFF; 128 | } 129 | uint8_t retval = 0; 130 | for(int i = 7; i + masklen > 7; i--) { 131 | retval |= 1 << i; 132 | } 133 | 134 | return retval; 135 | } 136 | 137 | int authorized_client(CLIENT *opts) { 138 | FILE *f ; 139 | char line[LINELEN]; 140 | 141 | if (opts->server->authname == NULL) { 142 | msg(LOG_INFO, "No authorization file, granting access."); 143 | return 1; 144 | } 145 | 146 | if ((f=fopen(opts->server->authname,"r"))==NULL) { 147 | msg(LOG_INFO, "Can't open authorization file %s (%s).", 148 | opts->server->authname, strerror(errno)); 149 | return 1 ; 150 | } 151 | 152 | while (fgets(line,LINELEN,f)!=NULL) { 153 | char* pos; 154 | char* endpos; 155 | /* Drop comments */ 156 | if((pos = strchr(line, '#'))) { 157 | *pos = '\0'; 158 | } 159 | /* Skip whitespace */ 160 | pos = line; 161 | while((*pos) && isspace(*pos)) { 162 | pos++; 163 | } 164 | /* Skip content-free lines */ 165 | if(!(*pos)) { 166 | continue; 167 | } 168 | /* Trim trailing whitespace */ 169 | endpos = pos; 170 | while ((*endpos) && !isspace(*endpos)) 171 | endpos++; 172 | *endpos = '\0'; 173 | if(address_matches(pos, (struct sockaddr*)&opts->clientaddr, NULL)) { 174 | fclose(f); 175 | return 1; 176 | } 177 | } 178 | fclose(f); 179 | return 0; 180 | } 181 | 182 | /** 183 | * duplicate server 184 | * @param s the old server we want to duplicate 185 | * @return new duplicated server 186 | **/ 187 | SERVER* dup_serve(const SERVER *const s) { 188 | SERVER *serve = NULL; 189 | 190 | serve=g_new0(SERVER, 1); 191 | if(serve == NULL) 192 | return NULL; 193 | 194 | if(s->exportname) 195 | serve->exportname = g_strdup(s->exportname); 196 | 197 | serve->expected_size = s->expected_size; 198 | 199 | if(s->listenaddr) 200 | serve->listenaddr = g_strdup(s->listenaddr); 201 | 202 | if(s->authname) 203 | serve->authname = g_strdup(s->authname); 204 | 205 | serve->flags = s->flags; 206 | serve->virtstyle = s->virtstyle; 207 | serve->cidrlen = s->cidrlen; 208 | 209 | if(s->prerun) 210 | serve->prerun = g_strdup(s->prerun); 211 | 212 | if(s->postrun) 213 | serve->postrun = g_strdup(s->postrun); 214 | 215 | if(s->transactionlog) 216 | serve->transactionlog = g_strdup(s->transactionlog); 217 | 218 | if(s->servename) 219 | serve->servename = g_strdup(s->servename); 220 | 221 | if(s->cowdir) 222 | serve->cowdir = g_strdup(s->cowdir); 223 | 224 | serve->max_connections = s->max_connections; 225 | 226 | return serve; 227 | } 228 | 229 | uint64_t size_autodetect(int fhandle) { 230 | off_t es; 231 | u64 bytes __attribute__((unused)); 232 | struct stat stat_buf; 233 | int error; 234 | 235 | #ifdef HAVE_SYS_MOUNT_H 236 | #ifdef HAVE_SYS_IOCTL_H 237 | #ifdef BLKGETSIZE64 238 | DEBUG("looking for export size with ioctl BLKGETSIZE64\n"); 239 | if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) { 240 | return bytes; 241 | } 242 | #endif /* BLKGETSIZE64 */ 243 | #endif /* HAVE_SYS_IOCTL_H */ 244 | #endif /* HAVE_SYS_MOUNT_H */ 245 | 246 | DEBUG("looking for fhandle size with fstat\n"); 247 | stat_buf.st_size = 0; 248 | error = fstat(fhandle, &stat_buf); 249 | if (!error) { 250 | /* always believe stat if a regular file as it might really 251 | * be zero length */ 252 | if (S_ISREG(stat_buf.st_mode) || (stat_buf.st_size > 0)) 253 | return (uint64_t)stat_buf.st_size; 254 | } else { 255 | DEBUG("fstat failed: %s", strerror(errno)); 256 | } 257 | 258 | DEBUG("looking for fhandle size with lseek SEEK_END\n"); 259 | es = lseek(fhandle, (off_t)0, SEEK_END); 260 | if (es > ((off_t)0)) { 261 | return (uint64_t)es; 262 | } else { 263 | DEBUG("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4))); 264 | } 265 | 266 | DEBUG("Could not find size of exported block device: %s", strerror(errno)); 267 | return UINT64_MAX; 268 | } 269 | 270 | int exptrim(struct nbd_request* req, CLIENT* client) { 271 | /* Caller did range checking */ 272 | assert(!(client->server->flags & F_READONLY)); 273 | assert(req->from + req->len <= client->exportsize); 274 | /* For copy-on-write, we should trim on the diff file. Not yet 275 | * implemented. */ 276 | if(client->server->flags & F_COPYONWRITE) { 277 | DEBUG("TRIM not supported yet on copy-on-write exports"); 278 | return 0; 279 | } 280 | if (client->server->flags & F_TREEFILES) { 281 | /* start address of first block to be trimmed */ 282 | off_t min = ( ( req->from + TREEPAGESIZE - 1 ) / TREEPAGESIZE) * TREEPAGESIZE; 283 | /* start address of first block NOT to be trimmed */ 284 | off_t max = ( ( req->from + req->len ) / TREEPAGESIZE) * TREEPAGESIZE; 285 | while (minexportname,client->exportsize,min); 287 | min+=TREEPAGESIZE; 288 | } 289 | DEBUG("Performed TRIM request on TREE structure from %llu to %llu", (unsigned long long) req->from, (unsigned long long) req->len); 290 | return 0; 291 | } 292 | FILE_INFO cur = g_array_index(client->export, FILE_INFO, 0); 293 | FILE_INFO next; 294 | int i = 1; 295 | do { 296 | if(iexport->len) { 297 | next = g_array_index(client->export, FILE_INFO, i); 298 | } else { 299 | next.fhandle = -1; 300 | next.startoff = client->exportsize; 301 | } 302 | if(cur.startoff <= req->from && next.startoff - cur.startoff >= req->len) { 303 | off_t reqoff = req->from - cur.startoff; 304 | off_t curlen = next.startoff - reqoff; 305 | off_t reqlen = curlen - reqoff > req->len ? req->len : curlen - reqoff; 306 | punch_hole(cur.fhandle, reqoff, reqlen); 307 | } 308 | cur = next; 309 | i++; 310 | } while(i < client->export->len && cur.startoff < (req->from + req->len)); 311 | DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req->from, (unsigned long long) req->len); 312 | return 0; 313 | } 314 | 315 | pthread_mutex_t cntmutex = PTHREAD_MUTEX_INITIALIZER; 316 | 317 | SERVER* serve_inc_ref(SERVER *s) { 318 | pthread_mutex_lock(&cntmutex); 319 | s->refcnt++; 320 | pthread_mutex_unlock(&cntmutex); 321 | return s; 322 | } 323 | 324 | SERVER* serve_dec_ref(SERVER *s) { 325 | pthread_mutex_lock(&cntmutex); 326 | if(--(s->refcnt) == 0) { 327 | g_free(s); 328 | s = NULL; 329 | } 330 | pthread_mutex_unlock(&cntmutex); 331 | return s; 332 | } 333 | 334 | void serve_clear_element(SERVER **server) { 335 | serve_dec_ref(*server); 336 | } 337 | -------------------------------------------------------------------------------- /man/nbdtab.5.sgml.in: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | --> 11 | 12 | 13 | Wouter"> 14 | Verhelst"> 15 | 16 | $Date: 2006-10-18 15:01:57 +0200 (wo, 18 okt 2006) $"> 17 | 19 | 5"> 20 | wouter@debian.org"> 21 | 22 | nbdtab"> 23 | 24 | 25 | Debian GNU/Linux"> 26 | GNU"> 27 | ]> 28 | 29 | 30 | 31 |
32 | &dhemail; 33 |
34 | 35 | &dhfirstname; 36 | &dhsurname; 37 | 38 | 39 | 2015 40 | &dhusername; 41 | 42 | &dhdate; 43 |
44 | 45 | &dhucpackage; 46 | 47 | &dhsection; 48 | 49 | 50 | &dhpackage; 51 | 52 | configuration file for nbd-client 53 | 54 | 55 | 56 | &dhpackage; 57 | 58 | 59 | 60 | 61 | DESCRIPTION 62 | 63 | This file allows to configure predefined connections for 64 | nbd-client. It may contain multiple definitions, one per line, 65 | each of which contains four space-separated fields. 66 | 67 | To connect a device specified in the nbdtab file, 68 | run nbd-client(8) with the short name of that 69 | device as the sole argument. It will then look up the required 70 | information in nbdtab, and make the 71 | connection. 72 | 73 | Fields are separated from one another by any number of space 74 | or tab characters; records are separated from one another by 75 | newline characters. The file may also contain any number of 76 | comments, which start with a '#' character and continue until the 77 | end of the line or the end of the file, whichever is first. 78 | 79 | Fields 80 | The file contains the following fields: 81 | 82 | 83 | The short name of the device file. That is, it should 84 | contain the name of the device without the leading 85 | /dev/ part; e.g., it could say 86 | nbd0. 87 | 88 | 89 | The hostname (in case of a TCP socket) or filename (in 90 | case of a unix domain socket) on which the server is 91 | listening. 92 | 93 | 94 | The name of the export as exported by 95 | nbd-server. 96 | 97 | 98 | Any extra options. This field is optional (no pun 99 | intended), and need not appear in a file if no options are 100 | necessary. The options recognized by 101 | nbd-client(8) are specified below, in the 102 | section "Options". Any unknown options in 103 | this field will produce a warning by 104 | nbd-client, unless they are prepended by 105 | an underscore ('_') character; the underscore is 106 | specifically reserved for local use, or for distribution 107 | customization. 108 | 109 | 110 | 111 | 112 | Options 113 | Every command-line nbd-client option 114 | which allows to configure specific options for a particular 115 | device node has a corresponding option in the 116 | nbdtab file, and vice versa; where this 117 | isn't the case, that is a bug. 118 | Individual options in this field should be separated from 119 | one another by the comma character. 120 | 121 | 122 | 123 | 124 | The block size for this export. If this option is 125 | not used, the kernel's default will be used 126 | instead. 127 | Corresponds to the option on the 128 | command line. 129 | 130 | 131 | 132 | 134 | 135 | The CA certificate file for TLS. Corresponds to the 136 | option on the command line. 137 | 138 | 139 | 140 | 141 | 142 | The certificate file for TLS. Corresponds to the 143 | option on the command line. 144 | 145 | 146 | 147 | 148 | 149 | The number of connections to use for this device. 150 | Corresponds to the option on the command 151 | line; see nbd-client(8) for more details on that 152 | option. 153 | 154 | 155 | 156 | 158 | 159 | The private key file for TLS. Corresponds to the 160 | option on the command line. 161 | 162 | 163 | 164 | 165 | 166 | Disable the use of NBD_OPT_GO in the conversation. 167 | Corresponds to the option on the command 168 | line. 169 | 170 | 171 | 172 | 173 | 174 | Persist the connection, using the semantics of the 175 | command-line option. 176 | 177 | 178 | 179 | 180 | 181 | The port on which to communicate with the 182 | nbd-server. Defaults to the 183 | IANA-assigned port for NBD, 10809. 184 | 185 | 186 | 187 | 188 | 189 | The GnuTLS priority string to use. 190 | Corresponds to the option on the 191 | command line. 192 | 193 | 194 | 195 | 196 | 197 | Optimize for swap; . 198 | 199 | 200 | 201 | 202 | 203 | The timeout. If this option is not specified, no 204 | timeout is configured. 205 | Corresponds to the option on the 206 | command line. 207 | 208 | 209 | 210 | 212 | 213 | The hostname for TLS purposes; 214 | 215 | 216 | 217 | 218 | 219 | 220 | Use a Unix Domain socket to connect to the server; 221 | . 222 | 223 | 224 | 225 | 226 | 227 | 228 | SEE ALSO 229 | 230 | nbd-server (1), nbd-client (8), nbd-trdump (8) 231 | 232 | 233 | 234 | 235 | AUTHOR 236 | The NBD kernel module and the NBD tools were originally 237 | written by Pavel Machek (pavel@ucw.cz) 238 | 239 | The Linux kernel module is now maintained by Paul Clements 240 | (Paul.Clements@steeleye.com), while the userland tools are 241 | maintained by &dhusername; (&dhemail;) 242 | 243 | On The Hurd there is a regular translator available to perform the 244 | client side of the protocol, and the use of 245 | nbd-client is not required. Please see the 246 | relevant documentation for more information. 247 | 248 | This manual page was written by &dhusername; (&dhemail;). 249 | Permission is granted to copy, distribute and/or modify this 250 | document under the terms of the GNU General 251 | Public License, version 2, as published by the Free Software 252 | Foundation. 253 | 254 | 255 | 256 | EXAMPLES 257 | A simple nbdtab file could look like 258 | this: 259 | 260 | # swap space, called "swapexport" on the server 261 | # optimize for swap, and try to reconnect upon disconnect. 262 | nbd0 nbdserver.example.com swapexport swap,persist 263 | # other export, called "data" on the server. No options for this one. 264 | nbd1 nbdserver.example.com data 265 | 266 | 267 |
268 | -------------------------------------------------------------------------------- /nbdsrv.h: -------------------------------------------------------------------------------- 1 | #ifndef NBDSRV_H 2 | #define NBDSRV_H 3 | 4 | #include "lfs.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include "nbd.h" 14 | 15 | /* Structures */ 16 | 17 | /** 18 | * Types of virtuatlization 19 | **/ 20 | typedef enum { 21 | VIRT_NONE=0, /**< No virtualization */ 22 | VIRT_IPLIT, /**< Literal IP address as part of the filename */ 23 | VIRT_IPHASH, /**< Replacing all dots in an ip address by a / before 24 | doing the same as in IPLIT */ 25 | VIRT_CIDR, /**< Every subnet in its own directory */ 26 | } VIRT_STYLE; 27 | 28 | /** 29 | * Variables associated with a server. 30 | **/ 31 | typedef struct { 32 | gchar* exportname; /**< (unprocessed) filename of the file we're exporting */ 33 | uint64_t expected_size; /**< size of the exported file as it was told to 34 | us through configuration */ 35 | gchar* listenaddr; /**< The IP address we're listening on */ 36 | char* authname; /**< filename of the authorization file */ 37 | int flags; /**< flags associated with this exported file */ 38 | VIRT_STYLE virtstyle;/**< The style of virtualization, if any */ 39 | uint8_t cidrlen; /**< The length of the mask when we use 40 | CIDR-style virtualization */ 41 | gchar* prerun; /**< command to be ran after connecting a client, 42 | but before starting to serve */ 43 | gchar* postrun; /**< command that will be ran after the client 44 | disconnects */ 45 | gchar* servename; /**< name of the export as selected by nbd-client */ 46 | int max_connections; /**< maximum number of opened connections */ 47 | int numclients; /**< number of clients connected to this export */ 48 | gchar* transactionlog;/**< filename for transaction log */ 49 | gchar* cowdir; /**< directory for copy-on-write diff files. */ 50 | int refcnt; /**< reference counter */ 51 | } SERVER; 52 | 53 | /** 54 | * Variables associated with a client connection 55 | */ 56 | typedef struct _client { 57 | uint64_t exportsize; /**< size of the file we're exporting */ 58 | char *clientname; /**< peer, in human-readable format */ 59 | struct sockaddr_storage clientaddr; /**< peer, in binary format, network byte order */ 60 | char *exportname; /**< (processed) filename of the file we're exporting */ 61 | GArray *export; /**< array of FILE_INFO of exported files; 62 | array size is always 1 unless we're doing 63 | the multiple file option */ 64 | pthread_rwlock_t export_lock; 65 | int net; /**< The actual client socket */ 66 | SERVER *server; /**< The server this client is getting data from */ 67 | char* difffilename; /**< filename of the copy-on-write file, if any */ 68 | int difffile; /**< filedescriptor of copyonwrite file. @todo shouldn't this be an array too? (cfr 69 | export) Or make -m and -c mutually exclusive */ 70 | uint32_t difffilelen; /**< number of pages in difffile */ 71 | uint32_t *difmap; /**< see comment on the global difmap for this one */ 72 | int transactionlogfd; /**< fd for transaction log */ 73 | char semname[100]; /**< name of the posix sem that protects access to the transaction log */ 74 | sem_t *logsem; /**< posix sem that protects access to the transaction log */ 75 | int clientfeats; /**< Client flags specified during negotiation */ 76 | int clientflags; /**< Internal flags for this client, as determined by nbd-server */ 77 | pthread_mutex_t lock; /**< socket lock */ 78 | void *tls_session; /**< TLS session context. Is NULL unless STARTTLS 79 | has been negotiated. */ 80 | int (*socket_read)(struct _client*, void* buf, size_t len); 81 | int (*socket_write)(struct _client*, const void* buf, size_t len); 82 | void (*socket_closed)(struct _client*); 83 | } CLIENT; 84 | 85 | /** 86 | * Variables associated with an open file 87 | **/ 88 | typedef struct { 89 | int fhandle; /**< file descriptor */ 90 | off_t startoff; /**< starting offset of this file */ 91 | } FILE_INFO; 92 | 93 | typedef struct { 94 | struct nbd_request *req; 95 | char *buf; 96 | size_t buflen; 97 | size_t current_offset; 98 | uint32_t current_len; 99 | unsigned int is_structured : 1; 100 | unsigned int df : 1; 101 | } READ_CTX; 102 | 103 | /* Constants and macros */ 104 | 105 | /** 106 | * Error domain common for all NBD server errors. 107 | **/ 108 | #define NBDS_ERR g_quark_from_static_string("server-error-quark") 109 | 110 | /** 111 | * NBD server error codes. 112 | **/ 113 | typedef enum { 114 | NBDS_ERR_CFILE_NOTFOUND, /**< The configuration file is not found */ 115 | NBDS_ERR_CFILE_MISSING_GENERIC, /**< The (required) group "generic" is missing */ 116 | NBDS_ERR_CFILE_KEY_MISSING, /**< A (required) key is missing */ 117 | NBDS_ERR_CFILE_VALUE_INVALID, /**< A value is syntactically invalid */ 118 | NBDS_ERR_CFILE_VALUE_UNSUPPORTED, /**< A value is not supported in this build */ 119 | NBDS_ERR_CFILE_NO_EXPORTS, /**< A config file was specified that does not 120 | define any exports */ 121 | NBDS_ERR_CFILE_INCORRECT_PORT, /**< The reserved port was specified for an 122 | old-style export. */ 123 | NBDS_ERR_CFILE_DIR_UNKNOWN, /**< A directory requested does not exist*/ 124 | NBDS_ERR_CFILE_READDIR_ERR, /**< Error occurred during readdir() */ 125 | NBDS_ERR_CFILE_INVALID_SPLICE, /**< We can't use splice with the other options 126 | specified for the export. */ 127 | NBDS_ERR_SO_LINGER, /**< Failed to set SO_LINGER to a socket */ 128 | NBDS_ERR_SO_REUSEADDR, /**< Failed to set SO_REUSEADDR to a socket */ 129 | NBDS_ERR_SO_KEEPALIVE, /**< Failed to set SO_KEEPALIVE to a socket */ 130 | NBDS_ERR_GAI, /**< Failed to get address info */ 131 | NBDS_ERR_SOCKET, /**< Failed to create a socket */ 132 | NBDS_ERR_BIND, /**< Failed to bind an address to socket */ 133 | NBDS_ERR_LISTEN, /**< Failed to start listening on a socket */ 134 | NBDS_ERR_SYS, /**< Underlying system call or library error */ 135 | NBDS_ERR_CFILE_INVALID_WAIT, /**< We can't use wait with the other options 136 | specified for the export. */ 137 | } NBDS_ERRS; 138 | 139 | /** 140 | * Logging macros. 141 | * 142 | * @todo remove this. We should use g_log in all cases, and use the 143 | * logging mangler to redirect to syslog if and when necessary. 144 | */ 145 | #ifdef ISSERVER 146 | #define msg(prio, ...) syslog(prio, __VA_ARGS__) 147 | #else 148 | #define msg(prio, ...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, __VA_ARGS__) 149 | #endif 150 | #define MY_NAME "nbd_server" 151 | 152 | /** Per-export flags: */ 153 | #define F_READONLY 1 /**< flag to tell us a file is readonly */ 154 | #define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */ 155 | #define F_COPYONWRITE 4 /**< flag to tell us a file is exported using 156 | copyonwrite */ 157 | #define F_AUTOREADONLY 8 /**< flag to tell us a file is set to autoreadonly */ 158 | #define F_SPARSE 16 /**< flag to tell us copyronwrite should use a sparse file */ 159 | #define F_SDP 32 /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */ 160 | #define F_SYNC 64 /**< Whether to fsync() after a write */ 161 | #define F_FLUSH 128 /**< Whether server wants FLUSH to be sent by the client */ 162 | #define F_FUA 256 /**< Whether server wants FUA to be sent by the client */ 163 | #define F_ROTATIONAL 512 /**< Whether server wants the client to implement the elevator algorithm */ 164 | #define F_TEMPORARY 1024 /**< Whether the backing file is temporary and should be created then unlinked */ 165 | #define F_TRIM 2048 /**< Whether server wants TRIM (discard) to be sent by the client */ 166 | #define F_FIXED 4096 /**< Client supports fixed new-style protocol (and can thus send us extra options */ 167 | #define F_TREEFILES 8192 /**< flag to tell us a file is exported using -t */ 168 | #define F_FORCEDTLS 16384 /**< TLS is required, either for the server as a whole or for a given export */ 169 | #define F_SPLICE 32768 /**< flag to tell us to use splice for read/write operations */ 170 | #define F_WAIT 65536 /**< flag to tell us to wait for file creation */ 171 | #define F_DATALOG 131072 /**< flag to tell us that the transaction log shall contain the written data */ 172 | 173 | /** Internal flags (for clientflags) */ 174 | 175 | #define F_STRUCTURED 1 176 | 177 | /* Functions */ 178 | 179 | /** 180 | * Check whether a given address matches a given netmask. 181 | * 182 | * @param mask the address or netmask to check against, in ASCII representation 183 | * @param addr the address to check 184 | * 185 | * @return true if the address matches the mask, false otherwise; in case of 186 | * failure to parse netmask, returns false with err set appropriately. 187 | * @todo decide what to do with v6-mapped IPv4 addresses. 188 | */ 189 | bool address_matches(const char* mask, const struct sockaddr* addr, GError** err); 190 | 191 | /** 192 | * Gets a byte to allow for address masking. 193 | * 194 | * @param masklen the length of the requested mask. 195 | * @return if the length of the mask is 8 or longer, 0xFF. Otherwise, a byte 196 | * with `masklen' number of leading bits set to 1, everything else set to 0. 197 | */ 198 | uint8_t getmaskbyte(int masklen) G_GNUC_PURE; 199 | 200 | /** 201 | * Check whether a client is allowed to connect. Works with an authorization 202 | * file which contains one line per machine or network, with CIDR-style 203 | * netmasks. 204 | * 205 | * @param opts The client who's trying to connect. 206 | * @return 0 - authorization refused, 1 - OK 207 | **/ 208 | int authorized_client(CLIENT *opts); 209 | 210 | /** 211 | * duplicate server 212 | * @param s the old server we want to duplicate 213 | * @return new duplicated server 214 | **/ 215 | SERVER* dup_serve(const SERVER *const s); 216 | 217 | /** 218 | * Detect the size of a file. 219 | * 220 | * @param fhandle An open filedescriptor 221 | * @return the size of the file, or UINT64_MAX if detection was 222 | * impossible. 223 | **/ 224 | uint64_t size_autodetect(int fhandle); 225 | 226 | /** 227 | * increase the ref counter for a SERVER 228 | * 229 | * @param s the server to increase 230 | **/ 231 | SERVER* serve_inc_ref(SERVER *s); 232 | 233 | /** 234 | * decrement the reference counter or a SERVER 235 | * 236 | * @param s the server to decrement 237 | **/ 238 | SERVER* serve_dec_ref(SERVER *s); 239 | 240 | /** 241 | * Punch a hole in the backend file (if supported by the current system). 242 | * 243 | * @param req the request for which this is being processed 244 | * @param client the client for which we're processing this request 245 | **/ 246 | int exptrim(struct nbd_request* req, CLIENT* client); 247 | #endif //NBDSRV_H 248 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Configure script for NBD system 2 | dnl (c) 1998 Martin Mares , (c) 2000 Pavel Machek , 3 | dnl (c) 2003-2024 Wouter Verhelst 4 | AC_INIT([nbd], 5 | m4_esyscmd(support/genver.sh | tr -d '\n'), 6 | [nbd@other.debian.org],, 7 | [http://nbd.sourceforge.net/]) 8 | m4_define([serial_tests], [ 9 | m4_esyscmd([automake --version | 10 | head -1 | 11 | awk '{split ($NF,a,"."); if (a[1] == 1 && a[2] >= 12) { print "serial-tests" }}' 12 | ]) 13 | ]) 14 | AM_INIT_AUTOMAKE(foreign dist-xz serial_tests subdir-objects) 15 | AM_MAINTAINER_MODE([enable]) 16 | AM_SILENT_RULES([yes]) 17 | AC_CONFIG_MACRO_DIR([support]) 18 | LT_INIT 19 | 20 | AC_ARG_ENABLE( 21 | lfs, 22 | AS_HELP_STRING([--disable-lfs],[Disable Large File Support (default on)]), 23 | [ 24 | if test "x$enableval" = "xyes" ; then 25 | NBD_LFS=1 26 | else 27 | NBD_LFS=0 28 | fi 29 | ], 30 | [NBD_LFS=1] 31 | ) 32 | AC_MSG_CHECKING([whether Large File Support should be enabled]) 33 | if test $NBD_LFS -eq 1; then 34 | AC_DEFINE(NBD_LFS,1, [Define to 1 if Large File Support should be enabled]) 35 | AC_MSG_RESULT([yes]) 36 | else 37 | AC_DEFINE(NBD_LFS,0) 38 | AC_MSG_RESULT([no]) 39 | fi 40 | 41 | AC_ARG_ENABLE( 42 | syslog, 43 | AS_HELP_STRING([--enable-syslog],[Enable Syslog logging]), 44 | [ 45 | if test "x$enableval" = "xyes" ; then 46 | ISSERVER=1 47 | else 48 | ISSERVER=0 49 | fi 50 | ], 51 | [ISSERVER=0] 52 | ) 53 | 54 | AC_MSG_CHECKING([whether syslog logging is requested]) 55 | if test $ISSERVER -eq 1; then 56 | AC_DEFINE(ISSERVER,1, [Define to 1 if you want nbd-server to log through syslog]) 57 | AC_MSG_RESULT([yes]) 58 | else 59 | AC_MSG_RESULT([no]) 60 | fi 61 | 62 | AC_ARG_ENABLE( 63 | debug, 64 | AS_HELP_STRING([--enable-debug],[Build a debugging version of the server]), 65 | [ 66 | if test "x$enableval" = "xyes"; then 67 | DODBG=1 68 | else 69 | DODBG=0 70 | fi 71 | ], 72 | [DODBG=0] 73 | ) 74 | 75 | AC_MSG_CHECKING([whether a debugging version is requested]) 76 | if test $DODBG -eq 1; then 77 | AC_MSG_RESULT([yes]) 78 | if test $ISSERVER -eq 1; then 79 | AC_MSG_ERROR([You requested both syslog logging and a debugging version of the server. Bad idea!]) 80 | fi 81 | AC_DEFINE(DODBG,1,[Define if you want a debugging version of nbd-server (lots of copious output)]) 82 | AC_DEFINE(NOFORK,1,[Define if you do not want the nbd-server to fork()]) 83 | else 84 | AC_MSG_RESULT([no]) 85 | fi 86 | 87 | AC_PROG_CC 88 | AC_PROG_CPP 89 | AC_PROG_INSTALL 90 | AM_PROG_LEX(noyywrap) 91 | m4_ifdef([AX_PROG_BISON],, 92 | [m4_fatal([The m4 macro AX_PROG_BISON has not been defined. Please install the autoconf-archive package.])]) 93 | AX_PROG_BISON([],AC_MSG_ERROR([bison is required])) 94 | PKG_PROG_PKG_CONFIG 95 | AC_CANONICAL_HOST 96 | AC_C_BIGENDIAN 97 | AC_C_INLINE 98 | AC_C_CONST 99 | AC_CHECK_SIZEOF(unsigned short int) 100 | AC_CHECK_SIZEOF(unsigned int) 101 | AC_CHECK_SIZEOF(unsigned long int) 102 | AC_CHECK_SIZEOF(unsigned long long int) 103 | AC_STRUCT_DIRENT_D_TYPE 104 | AC_CHECK_FUNCS([llseek alarm gethostbyname inet_ntoa memset socket strerror strstr mkstemp fdatasync]) 105 | HAVE_FL_PH=no 106 | 107 | AC_CHECK_FUNC(fallocate, 108 | [ 109 | AC_CHECK_HEADERS([linux/falloc.h]) 110 | if test "x$ac_cv_header_linux_falloc_h" = "xyes" 111 | then 112 | AC_CHECK_DECL(FALLOC_FL_PUNCH_HOLE, [HAVE_FL_PH=yes], [HAVE_FL_PH=no], [[#include ]]) 113 | fi 114 | ] 115 | ) 116 | 117 | AC_MSG_CHECKING([for FALLOC_FL_PUNCH_HOLE support]) 118 | if test "x$HAVE_FL_PH" = "xyes" 119 | then 120 | AC_DEFINE(HAVE_FALLOC_PH, 1, [Define to 1 if you have FALLOC_FL_PUNCH_HOLE]) 121 | AC_MSG_RESULT([yes]) 122 | else 123 | AC_DEFINE(HAVE_FALLOC_PH, 0, [Define to 1 if you have FALLOC_FL_PUNCH_HOLE]) 124 | AC_MSG_RESULT([no]) 125 | fi 126 | 127 | AC_CHECK_DECL([BLKDISCARD], AC_DEFINE(HAVE_BLKDISCARD, 1, [Define to 1 if you have the BLKDISCARD ioctl]), AC_DEFINE(HAVE_BLKDISCARD, 0), [#include ]) 128 | 129 | AC_CHECK_FUNC(splice, [HAVE_SPLICE=yes], [HAVE_SPLICE=no]) 130 | if test "$HAVE_SPLICE" = "yes" 131 | then 132 | HAVE_SETPIPE_SZ=no 133 | AC_CHECK_DECL(F_SETPIPE_SZ, [HAVE_SETPIPE_SZ=yes], 134 | [ 135 | unset ac_cv_have_decl_F_SETPIPE_SZ 136 | AC_CHECK_HEADERS([linux/fcntl.h]) 137 | if test "$ac_cv_header_linux_fcntl_h" = "yes" 138 | then 139 | AC_CHECK_DECL(F_SETPIPE_SZ, [HAVE_SETPIPE_SZ=define], [HAVE_SETPIPE_SZ=no], [[#include ]]) 140 | fi 141 | ], 142 | [[ 143 | #define _GNU_SOURCE 144 | #include 145 | ]] 146 | ) 147 | AC_MSG_CHECKING([for F_SETPIPE_SZ support]) 148 | case $HAVE_SETPIPE_SZ in 149 | yes) 150 | AC_DEFINE(HAVE_SPLICE, 1, [Define to 1 if we have splice support]) 151 | AC_MSG_RESULT([yes]) 152 | ;; 153 | define) 154 | AC_DEFINE(HAVE_SPLICE, 1, [Define to 1 if we have splice support]) 155 | AC_DEFINE(F_SETPIPE_SZ, 1031, [Define to 1031 if we have kernel support but no userspace support]) 156 | AC_MSG_RESULT([yes]) 157 | ;; 158 | no) 159 | AC_MSG_RESULT([missing, disabling splice support]) 160 | ;; 161 | esac 162 | fi 163 | 164 | m4_ifndef([PKG_CHECK_MODULES], [m4_fatal([Missing pkg-config M4 macros. Please ensure that pkg-config is installed.])]) 165 | 166 | dnl AC_MSG_CHECKING([where to puth systemd unit files]) 167 | dnl AC_ARG_WITH( 168 | dnl systemd, 169 | dnl AS_HELP_STRING([--with-systemd=loc|pkgconfig],[Install systemd files in loc; if passing pkgconfig, use pkg-config to detect the correct location and install there.]) 170 | dnl [ 171 | dnl if test "x$enableval" = "xyes"; then 172 | dnl ENABLE_SYSTEMD=yes 173 | dnl else 174 | dnl ENABLE_SYSTEMD=no 175 | dnl fi 176 | dnl ],[] 177 | dnl ) 178 | dnl 179 | dnl if test "x$ENABLE_SYSTEMD" != "xno"; then 180 | dnl PKG_CHECK_VAR([SYSTEMDUNIT],[systemd],systemdsystemunitdir],[AC_SUBST([SYSTEMDLOC], [$SYSTEMDUNIT])]) 181 | dnl fi 182 | dnl AM_CONDITIONAL(SYSTEMD, [test ! -z "$SYSTEMDUNIT"]) 183 | dnl if test ! -z $SYSTEMDUNIT; then 184 | dnl AC_MSG_RESULT([$SYSTEMDUNIT]) 185 | dnl else 186 | dnl case $ENABLE_SYSTEMD in 187 | dnl no) 188 | dnl AC_MSG_RESULT([disabled]) 189 | dnl ;; 190 | dnl yes) 191 | dnl AC_MSG_ERROR([systemd not found]) 192 | dnl ;; 193 | dnl *) 194 | dnl AC_MSG_RESULT([not found]) 195 | dnl ;; 196 | dnl esac 197 | dnl fi 198 | 199 | AC_ARG_WITH([gnutls], 200 | [AS_HELP_STRING([--without-gnutls], 201 | [do not use gnutls])], 202 | [], 203 | [with_gnutls=check] 204 | ) 205 | if test "x$with_gnutls" != "xno"; then 206 | PKG_CHECK_MODULES(GnuTLS, [gnutls >= 2.12.0], 207 | [HAVE_GNUTLS=1 208 | AC_DEFINE(HAVE_GNUTLS, 1, [Define to 1 if you have a GnuTLS version of 2.12 or above])], 209 | [if test "x$with_gnutls" = "xyes"; then 210 | AC_MSG_ERROR([--with-gnutls given but cannot find gnutls]) 211 | else 212 | HAVE_GNUTLS=0 213 | AC_DEFINE(HAVE_GNUTLS, 0) 214 | fi] 215 | ) 216 | else 217 | HAVE_GNUTLS=0 218 | AC_DEFINE(HAVE_GNUTLS, 0) 219 | fi 220 | AM_CONDITIONAL([GNUTLS], [test "x$HAVE_GNUTLS" = "x1"]) 221 | 222 | AC_CHECK_HEADERS([winioctl.h], [], [], 223 | [#include 224 | #include 225 | #include 226 | ]) 227 | HAVE_FSCTL_SET_ZERO_DATA=no 228 | if test "x$ac_cv_header_winioctl_h" = "xyes" 229 | then 230 | AC_CHECK_DECL(FSCTL_SET_ZERO_DATA, [HAVE_FSCTL_SET_ZERO_DATA=yes], [HAVE_FSCTL_SET_ZERO_DATA=no], 231 | [#include 232 | #include 233 | #include 234 | ]) 235 | fi 236 | if test "x$HAVE_FSCTL_SET_ZERO_DATA" = "xyes" 237 | then 238 | AC_DEFINE(HAVE_FSCTL_SET_ZERO_DATA, 1, [Define to 1 if you have FSCTL_SET_ZERO_DATA]) 239 | else 240 | AC_DEFINE(HAVE_FSCTL_SET_ZERO_DATA, 0, [Define to 1 if you have FSCTL_SET_ZERO_DATA]) 241 | fi 242 | 243 | AC_CHECK_FUNC([sync_file_range], 244 | [AC_DEFINE([HAVE_SYNC_FILE_RANGE], [sync_file_range(2) is not supported], [sync_file_range(2) is supported])], 245 | []) 246 | AC_FUNC_FORK 247 | AC_MSG_CHECKING(whether client should be built) 248 | AS_CASE([$host_os], 249 | [linux*], [NBD_CLIENT_NAME="nbd-client"; AC_MSG_RESULT(yes)], 250 | [NBD_CLIENT_NAME=""; AC_MSG_RESULT(no)] 251 | ) 252 | AC_MSG_CHECKING(whether to expect tlshuge test to fail) 253 | AS_CASE([$host_os], 254 | [darwin*], [RUN_XFAIL=tlshuge; AC_MSG_RESULT(yes)], 255 | [RUN_XFAIL=""; AC_MSG_RESULT(no)] 256 | ) 257 | AC_SUBST([RUN_XFAIL]) 258 | AM_CONDITIONAL(CLIENT, [test ! -z "$NBD_CLIENT_NAME"]) 259 | AC_SEARCH_LIBS(bind, socket,, AC_MSG_ERROR([Could not find an implementation of the bind() system call])) 260 | AC_SEARCH_LIBS(inet_ntoa, nsl,, AC_MSG_ERROR([Could not find an implementation of the inet_ntoa() system call])) 261 | AC_SEARCH_LIBS(daemon, resolv,, AC_MSG_ERROR([Could not find an implementation of the daemon() system call])) 262 | AC_CHECK_HEADERS([sys/mount.h],,, 263 | [[#include 264 | ]]) 265 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h sys/ioctl.h sys/socket.h syslog.h linux/types.h sys/dirent.h sys/uio.h]) 266 | PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.32.0 gthread-2.0 >= 2.32.0], [HAVE_GLIB=yes], AC_MSG_ERROR([Missing glib])) 267 | #PKG_CHECK_MODULES(SW, [socket_wrapper], [HAVE_SW=yes], [HAVE_SW=no]) 268 | #PKG_CHECK_MODULES(NW, [nss_wrapper], [HAVE_NW=yes], [HAVE_NW=no]) 269 | #AM_CONDITIONAL(CWRAP, test "$HAVE_SW" = "yes" -a "$HAVE_NW" = "yes") 270 | 271 | my_save_cflags="$CFLAGS" 272 | my_save_libs="$LIBS" 273 | CFLAGS="-Wdeprecated-declarations -Werror $GLIB_CFLAGS" 274 | LIBS="$GLIB_LIBS" 275 | dnl g_memdup2 added in glib-2.68 276 | AC_CHECK_FUNCS([g_memdup2]) 277 | CFLAGS="$my_save_cflags" 278 | LIBS="$my_save_libs" 279 | 280 | AC_MSG_CHECKING([whether _BSD_SOURCE needs to be defined for DT_* macros]) 281 | AC_PREPROC_IFELSE( 282 | [AC_LANG_PROGRAM([[#include ]], 283 | [[#ifndef DT_UNKNOWN 284 | #error nope 285 | #endif]])], 286 | [AC_MSG_RESULT([no]); NEED_BSD_SOURCE=0], 287 | [AC_MSG_RESULT([yes]); NEED_BSD_SOURCE=1]) 288 | AC_DEFINE([NEED_BSD_SOURCE], $NEED_BSD_SOURCE, [Define to 1 if _BSD_SOURCE needs to be defined before certain inclusions]) 289 | 290 | AC_ARG_WITH([libnl], 291 | [AS_HELP_STRING([--without-libnl], 292 | [do not use libnl])], 293 | [], 294 | [with_libnl=check] 295 | ) 296 | if test "x$with_libnl" != "xno"; then 297 | PKG_CHECK_MODULES(LIBNL3, libnl-genl-3.0 >= 3.1, 298 | [HAVE_NETLINK=1 299 | AC_DEFINE(HAVE_NETLINK, 1, [Define to 1 if we have netlink support]) 300 | CFLAGS="$CFLAGS $LIBNL3_CFLAGS" 301 | LIBS="$LIBS $LIBNL3_LIBS"], 302 | [if test "x$with_libnl" = "xyes"; then 303 | AC_MSG_ERROR([--with-libnl given but cannot find libnl]) 304 | else 305 | HAVE_NETLINK=0 306 | AC_DEFINE(HAVE_NETLINK, 0) 307 | fi] 308 | ) 309 | else 310 | HAVE_NETLINK=0 311 | AC_DEFINE(HAVE_NETLINK, 0, [Define to 1 if we have netlink support]) 312 | fi 313 | 314 | AM_CONDITIONAL(NETLINK, [test "$HAVE_NETLINK" = "1"]) 315 | 316 | AC_MSG_CHECKING([whether man pages are requested]) 317 | AC_ARG_ENABLE([manpages], 318 | AS_HELP_STRING([--disable-manpages], [Do not install man pages]), 319 | [], 320 | [enable_manpages=check] 321 | ) 322 | AC_MSG_RESULT([$enable_manpages]) 323 | 324 | AS_IF([test "x$enable_manpages" != "xno"], [ 325 | AC_CHECK_PROG([DB2M], docbook2man, [docbook2man]) 326 | ]) 327 | AS_IF([test "x$enable_manpages" = "xyes" -a "x$DB2M" = "x"], [ 328 | AC_MSG_ERROR([docbook2man not found, but is required to build manpages]) 329 | ]) 330 | if test "x$enable_manpages" = "xcheck"; then 331 | if test "x$DB2M" = "x"; then 332 | enable_manpages=no 333 | else 334 | enable_manpages=yes 335 | fi 336 | fi 337 | AC_MSG_CHECKING([whether to build manpages]) 338 | AC_MSG_RESULT([$enable_manpages]) 339 | 340 | AM_CONDITIONAL(MANPAGES, test "x$enable_manpages" = "xyes") 341 | AS_IF([test "x$enable_manpages" != "xno"], [ 342 | AC_SUBST([MAN_CONFIG_FILES],["\ 343 | man/nbd-client.8.sgml \ 344 | man/nbd-server.5.sgml \ 345 | man/nbd-server.1.sgml \ 346 | man/nbd-trdump.1.sgml \ 347 | man/nbd-trplay.1.sgml \ 348 | man/nbdtab.5.sgml \ 349 | "]) 350 | ]) 351 | MAN_PREFIX="$prefix" 352 | test "x$MAN_PREFIX" = "xNONE" && MAN_PREFIX="$ac_default_prefix" 353 | AC_SUBST([MAN_PREFIX]) 354 | MAN_EXEC_PREFIX=$(eval echo "$exec_prefix") 355 | test "x$MAN_EXEC_PREFIX" = "xNONE" && MAN_EXEC_PREFIX="$MAN_PREFIX" 356 | AC_SUBST([MAN_EXEC_PREFIX]) 357 | MAN_SYSCONFDIR=$(eval echo "$sysconfdir") 358 | test "x$MAN_SYSCONFDIR" = "xNONE/etc" && MAN_SYSCONFDIR="$MAN_PREFIX/etc" 359 | AC_SUBST([MAN_SYSCONFDIR]) 360 | 361 | AC_HEADER_SYS_WAIT 362 | AC_TYPE_OFF_T 363 | AC_TYPE_PID_T 364 | AM_CPPFLAGS=$AM_CPPFLAGS" -DSYSCONFDIR='\"$sysconfdir\"'" 365 | AC_SUBST(AM_CPPFLAGS) 366 | AM_CONDITIONAL(GZNBD, [test "x$ENABLE_GZNBD" = "xyes"]) 367 | AC_CONFIG_HEADERS([config.h]) 368 | AC_CONFIG_LINKS([tests/run/buffer.c:buffer.c 369 | tests/run/crypto-gnutls.c:crypto-gnutls.c 370 | tests/run/cliserv.c:cliserv.c]) 371 | AC_CONFIG_FILES([Makefile 372 | doc/Doxyfile 373 | doc/Makefile 374 | man/Makefile 375 | tests/Makefile 376 | tests/code/Makefile 377 | tests/run/Makefile 378 | tests/parse/Makefile 379 | $MAN_CONFIG_FILES 380 | systemd/Makefile 381 | systemd/nbd@.service.sh 382 | ]) 383 | AC_OUTPUT 384 | 385 | -------------------------------------------------------------------------------- /man/nbd-server.1.sgml.in: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | --> 11 | 12 | 13 | Wouter"> 14 | Verhelst"> 15 | 16 | $Date$"> 17 | 19 | 1"> 20 | wouter@debian.org"> 21 | 22 | nbd-server"> 23 | 24 | 25 | Debian GNU/Linux"> 26 | GNU"> 27 | ]> 28 | 29 | 30 | 31 |
32 | &dhemail; 33 |
34 | 35 | &dhfirstname; 36 | &dhsurname; 37 | 38 | 39 | 2001 40 | &dhusername; 41 | 42 | &dhdate; 43 |
44 | 45 | &dhucpackage; 46 | 47 | &dhsection; 48 | 49 | 50 | &dhpackage; 51 | 52 | serve a file as a block device to other computers 53 | running the &gnu;/Linux(tm) or &gnu;/Hurd Operating 54 | System 55 | 56 | 57 | 58 | &dhpackage; 59 | 60 | [ip@]port 61 | filename 62 | size 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | DESCRIPTION 77 | 78 | &dhpackage; is the server for the Linux 79 | Network Block Device (NBD). With NBD, a client can use a file, 80 | exported over the network from a server, as a block device. It can 81 | then be used for whatever purpose a normal block device (harddisk, 82 | CD-ROM, ...) can be used for. 83 | 84 | NBD can be useful for diskless clients that need swapspace, 85 | but you can also create a filesystem on it and use it as though it 86 | were a local filesystem. 87 | 88 | &dhpackage; implements some security 89 | through a file called "@MAN_SYSCONFDIR@/nbd-server/allow" (by default; a 90 | different file can be chosen with the '-l' option or through a 91 | config file specification). This file must list the IP-addresses or 92 | network masks of clients that are allowed to connect. If it does not 93 | exist, all clients are able to connect. If the file is empty, no 94 | clients can connect. 95 | 96 | Note that while the command line allows for specifying an 97 | export, the use of this option is deprecated. It is preferred to 98 | make use of a configuration file instead, the format of which is 99 | defined in nbd-server(5). 100 | 101 | While nbd-server is running, new exports can be added by 102 | re-writing configuration files and then sending SIGHUP to 103 | nbd-server. SIGHUP causes nbd-server to re-read its configuration 104 | files and to start serving all new exports which were not served 105 | earlier. Reconfiguration does not modify any existing export, it only 106 | appends new ones. 107 | 108 | 109 | OPTIONS 110 | 111 | 112 | 113 | ip 114 | 115 | The ip address the server should listen on. This may 116 | be an IPv4 address, an IPv6 address, or a hostname. In the 117 | latter case, nbd-server will do a hostname lookup for the 118 | name specified, and will listen on the first address that is 119 | returned. For compatibility with past versions of 120 | nbd-server, if an IPv4 address is specified, the @ sign that 121 | serves as separator between the address and port may be 122 | replaced by a colon. 123 | If this parameter is not specified, nbd-server will 124 | listen on all local addresses on both IPv4 and IPv6. To 125 | limit to IPv4, specify the address as 0.0.0.0; to limit to 126 | IPv6, specify it as ::. 127 | 128 | 129 | 130 | 131 | 132 | 133 | The port the server should listen to. A valid port is 134 | any number between 1 and 65536; if 0 is used, nbd-server 135 | will listen on stdin (so that nbd-server can be ran from 136 | inetd) 137 | 138 | 139 | 140 | 141 | 142 | The filename of the file that should be exported. This 143 | can be any file, including "real" blockdevices (i.e. a file 144 | from /dev). If the filename includes the literal string 145 | "%s", then this %s will be substituded with the IP-address 146 | of the client trying to connect. 147 | 148 | 149 | 150 | 151 | 152 | The size of the block device at the client side. This 153 | is especially useful in conjunction with the -m 154 | option 155 | Can optionally be followed by one of K,k,M or 156 | m, in which case the size will be multiplied by 1024 (K 157 | or k) or 1048576 (M or m) 158 | 159 | 160 | 161 | 162 | 163 | Export the file read-only. If a client tries to write 164 | to a read-only exported file, it will receive an error, but 165 | the connection will stay up. 166 | 167 | 168 | 169 | 170 | 171 | Work with multiple files. This can be used to export 172 | blockdevices that are larger than the maximum allowed 173 | filesize on a given filesystem; i.e. when the filesystem 174 | does not allow files larger than 2GB (which is true for 175 | Linux 2.2 and below), you can use this option to store the 176 | data in multiple files and export a larger filesystem, if 177 | needed. 178 | 179 | To use this option, you must create a number of files 180 | with names in the format "name.X", where "name" is given as 181 | the filename argument to nbd-server, and "X" is a number 182 | starting by 0 and going up for each file. 183 | 184 | 185 | Allowing more flexibility for this option is planned for 186 | future versions. 187 | 188 | 189 | 190 | 191 | 192 | Copy on write. When this option is provided, 193 | write-operations are not done to the exported file, but to a 194 | separate file. This separate file is removed when the 195 | connection is closed, which means that serving this way will 196 | make nbd-server slow down (especially on large block devices 197 | with lots of writes), and that after disconnecting and 198 | reconnecting the client or the server, all changes are 199 | lost. 200 | 201 | 202 | 203 | 204 | 205 | Specify configuration file. The default configuration 206 | file, if this parameter is not specified, is 207 | @MAN_SYSCONFDIR@/nbd-server/config. 208 | Note that the configuration file is always parsed and 209 | the entries in the file used, even if an extra server is 210 | specified on the command line. To disable the configuration 211 | file entirely, either move it away or use the -C option to 212 | point nbd-server(1) to a non-existing or 213 | empty configuration file. 214 | Also note that if an empty, incomplete, or invalid 215 | configuration file is specified, nbd-server will produce a 216 | warning about failure to parse the config file. If the 217 | command line contains a fully specified configuration, this 218 | warning is harmless and may be ignored. 219 | 220 | 221 | 222 | 223 | 224 | Specify the maximum number of opened connections. If this 225 | parameter is not specified, no limit is set. 226 | 227 | 228 | 229 | 230 | 231 | Output the version of nbd-server, and exit. 232 | 233 | 234 | 235 | 236 | 237 | Do not daemonize the main process. In contrast 238 | to , this still allows to fork the 239 | serving process for a client from the main process. 240 | 241 | 242 | 243 | 244 | 245 | Do not fork. Useful for debugging. 246 | Implies . 247 | 248 | 249 | 250 | 251 | 252 | This argument should contain a list of IP-addresses 253 | for hosts that may connect to the server. Wildcards are 254 | not allowed. If the file does not 255 | exist, it is ignored (and any host can connect); If the file 256 | does exist, but is empty, no host can connect. By default, 257 | the name 'nbd_server.allow' is used, and looked for in the 258 | current directory, unless nbd-server is compiled as a 259 | daemon, in which case it is looked for in the 260 | root-directory. 261 | 262 | 263 | 264 | 265 | 266 | If the argument is given on the 267 | command line, then &dhpackage; will output a configuration 268 | file section with this as the header that is functionally 269 | equivalent to the other options specified on the command line, 270 | and exit. This is useful for migrating pre-2.9 nbd-server 271 | initscript configuration files to the new format. 272 | 273 | 274 | 275 | 276 | 277 | 278 | EXAMPLES 279 | Some examples of nbd-server usage: 280 | 281 | 282 | To export a file /export/nbd/exp-bl-dev on port 2000: 283 | nbd-server 2000 /export/nbd/exp-bl-dev 284 | 285 | 286 | To export a the same file read-only: 287 | nbd-server 2000 /export/nbd/exp-bl-dev -r 288 | 289 | 290 | To export the same file read-write, but make sure 291 | changes are lost after restarting the client or the 292 | server: 293 | nbd-server 2000 /export/nbd/exp-bl-dev 294 | -c 295 | 296 | 297 | 298 | 299 | SEE ALSO 300 | 301 | nbd-client (8), nbd-server (5), nbd-trdump (8) 302 | 303 | 304 | 305 | AUTHOR 306 | The NBD kernel module and the NBD tools were originally 307 | written by Pavel Machek (pavel@ucw.cz) 308 | 309 | The Linux kernel module is now maintained by Paul Clements 310 | (Paul.Clements@steeleye.com), while the userland tools are 311 | maintained by &dhusername; (&dhemail;) 312 | 313 | On The Hurd there is a regular translator available to perform the 314 | client side of the protocol, and the use of 315 | nbd-client is not required. Please see the 316 | relevant documentation for more information. 317 | 318 | This manual page was written by &dhusername; (&dhemail;) for 319 | the &debian; system (but may be used by others). Permission is 320 | granted to copy, distribute and/or modify this document under 321 | the terms of the GNU General Public License, 322 | version 2, as published by the Free Software Foundation. 323 | 324 | 325 |
326 | -------------------------------------------------------------------------------- /crypto-gnutls.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 Wrymouth Innovation Ltd 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | #define _GNU_SOURCE 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "crypto-gnutls.h" 47 | #include "buffer.h" 48 | 49 | #define MAX_CERTS 10 50 | 51 | #define FALSE 0 52 | #define TRUE 1 53 | 54 | #define PRIORITY "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2" 55 | 56 | struct tlssession 57 | { 58 | gnutls_certificate_credentials_t creds; 59 | gnutls_session_t session; 60 | char *hostname; 61 | int (*quitfn) (void *opaque); 62 | int (*erroutfn) (void *opaque, const char *format, va_list ap); 63 | int debug; 64 | void *opaque; 65 | }; 66 | 67 | #define BUF_SIZE 65536 68 | #define BUF_HWM ((BUF_SIZE*3)/4) 69 | 70 | static int 71 | falsequit (void *opaque) 72 | { 73 | return FALSE; 74 | } 75 | 76 | static int 77 | quit (tlssession_t * s) 78 | { 79 | return s->quitfn (s->opaque); 80 | } 81 | 82 | 83 | static int 84 | stderrout (void *opaque, const char *format, va_list ap) 85 | { 86 | return vfprintf (stderr, format, ap); 87 | } 88 | 89 | static int 90 | errout (tlssession_t * s, const char *format, ...) 91 | { 92 | va_list ap; 93 | int ret; 94 | va_start (ap, format); 95 | ret = s->erroutfn (s->opaque, format, ap); 96 | va_end (ap); 97 | return ret; 98 | } 99 | 100 | static int 101 | debugout (tlssession_t * s, const char *format, ...) 102 | { 103 | va_list ap; 104 | int ret = 0; 105 | va_start (ap, format); 106 | if (s->debug) 107 | ret = s->erroutfn (s->opaque, format, ap); 108 | va_end (ap); 109 | return ret; 110 | } 111 | 112 | static int 113 | socksetnonblock (int fd, int nb) 114 | { 115 | int sf = fcntl (fd, F_GETFL, 0); 116 | if (sf == -1) 117 | return -1; 118 | return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK)); 119 | } 120 | 121 | /* From (public domain) example file in GNUTLS 122 | * 123 | * This function will try to verify the peer's certificate, and 124 | * also check if the hostname matches, and the activation, expiration dates. 125 | */ 126 | static int 127 | verify_certificate_callback (gnutls_session_t session) 128 | { 129 | unsigned int status; 130 | const gnutls_datum_t *cert_list; 131 | unsigned int cert_list_size; 132 | int ret; 133 | gnutls_x509_crt_t cert; 134 | tlssession_t *s; 135 | 136 | /* read session pointer */ 137 | s = (tlssession_t *) gnutls_session_get_ptr (session); 138 | 139 | /* This verification function uses the trusted CAs in the credentials 140 | * structure. So you must have installed one or more CA certificates. 141 | */ 142 | ret = gnutls_certificate_verify_peers2 (session, &status); 143 | if (ret < 0) 144 | { 145 | debugout (s, "Could not verfify peer certificate due to an error\n"); 146 | return GNUTLS_E_CERTIFICATE_ERROR; 147 | } 148 | 149 | if (status & GNUTLS_CERT_INVALID) 150 | debugout (s, "The certificate is not trusted.\n"); 151 | 152 | if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) 153 | debugout (s, "The certificate hasn't got a known issuer.\n"); 154 | 155 | if (status & GNUTLS_CERT_REVOKED) 156 | debugout (s, "The certificate has been revoked.\n"); 157 | 158 | if (status & GNUTLS_CERT_EXPIRED) 159 | debugout (s, "The certificate has expired\n"); 160 | 161 | if (status & GNUTLS_CERT_NOT_ACTIVATED) 162 | debugout (s, "The certificate is not yet activated\n"); 163 | 164 | if (status) 165 | return GNUTLS_E_CERTIFICATE_ERROR; 166 | 167 | if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) 168 | return GNUTLS_E_CERTIFICATE_ERROR; 169 | 170 | if (gnutls_x509_crt_init (&cert) < 0) 171 | { 172 | debugout (s, "error in initialization\n"); 173 | return GNUTLS_E_CERTIFICATE_ERROR; 174 | } 175 | 176 | cert_list = gnutls_certificate_get_peers (session, &cert_list_size); 177 | if (cert_list == NULL) 178 | { 179 | debugout (s, "No certificate was found!\n"); 180 | return GNUTLS_E_CERTIFICATE_ERROR; 181 | } 182 | 183 | /* check only the first certificate - seems to be what curl does */ 184 | if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) 185 | { 186 | debugout (s, "error parsing certificate\n"); 187 | return GNUTLS_E_CERTIFICATE_ERROR; 188 | } 189 | 190 | if (s->hostname && *s->hostname) 191 | { 192 | if (!gnutls_x509_crt_check_hostname (cert, s->hostname)) 193 | { 194 | debugout (s, 195 | "The certificate's owner does not match hostname '%s'\n", 196 | s->hostname); 197 | return GNUTLS_E_CERTIFICATE_ERROR; 198 | } 199 | } 200 | 201 | gnutls_x509_crt_deinit (cert); 202 | 203 | debugout (s, "Peer passed certificate verification\n"); 204 | 205 | /* notify gnutls to continue handshake normally */ 206 | return 0; 207 | } 208 | 209 | tlssession_t * 210 | tlssession_new (int isserver, 211 | char *keyfile, char *certfile, char *cacertfile, 212 | char *hostname, char *priority, int insecure, int debug, 213 | int (*quitfn) (void *opaque), 214 | int (*erroutfn) (void *opaque, const char *format, 215 | va_list ap), void *opaque) 216 | { 217 | int ret; 218 | tlssession_t *s = calloc (1, sizeof (tlssession_t)); 219 | 220 | if (quitfn) 221 | s->quitfn = quitfn; 222 | else 223 | s->quitfn = falsequit; 224 | 225 | if (erroutfn) 226 | s->erroutfn = erroutfn; 227 | else 228 | s->erroutfn = stderrout; 229 | 230 | if (hostname) 231 | s->hostname = strdup (hostname); 232 | 233 | s->debug = debug; 234 | 235 | if (gnutls_certificate_allocate_credentials (&s->creds) < 0) 236 | { 237 | errout (s, "Certificate allocation memory error\n"); 238 | goto error; 239 | } 240 | 241 | if (cacertfile != NULL) 242 | { 243 | ret = 244 | gnutls_certificate_set_x509_trust_file (s->creds, cacertfile, 245 | GNUTLS_X509_FMT_PEM); 246 | if (ret < 0) 247 | { 248 | errout (s, "Error setting the x509 trust file: %s\n", 249 | gnutls_strerror (ret)); 250 | goto error; 251 | } 252 | 253 | if (!insecure) 254 | { 255 | gnutls_certificate_set_verify_function (s->creds, 256 | verify_certificate_callback); 257 | gnutls_certificate_set_verify_flags (s->creds, 258 | GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); 259 | } 260 | } 261 | 262 | if (keyfile && !certfile) 263 | certfile = keyfile; 264 | 265 | if (certfile != NULL && keyfile != NULL) 266 | { 267 | ret = 268 | gnutls_certificate_set_x509_key_file (s->creds, certfile, keyfile, 269 | GNUTLS_X509_FMT_PEM); 270 | 271 | if (ret < 0) 272 | { 273 | errout (s, 274 | "Error loading certificate or key file (%s, %s): %s\n", 275 | certfile, keyfile, gnutls_strerror (ret)); 276 | goto error; 277 | } 278 | } 279 | 280 | if (isserver) 281 | { 282 | ret = gnutls_init (&s->session, GNUTLS_SERVER); 283 | } 284 | else 285 | { 286 | ret = gnutls_init (&s->session, GNUTLS_CLIENT); 287 | } 288 | if (ret < 0) 289 | { 290 | errout (s, "Cannot initialize GNUTLS session: %s\n", 291 | gnutls_strerror (ret)); 292 | goto error; 293 | } 294 | 295 | gnutls_session_set_ptr (s->session, (void *) s); 296 | 297 | ret = gnutls_set_default_priority (s->session); 298 | if (ret < 0) 299 | { 300 | errout (s, "Cannot set default GNUTLS session priority: %s\n", 301 | gnutls_strerror (ret)); 302 | goto error; 303 | } 304 | 305 | const char *errpos = NULL; 306 | ret = gnutls_priority_set_direct (s->session, priority ? priority : PRIORITY, 307 | &errpos); 308 | if (ret < 0) 309 | { 310 | errout (s, "Cannot set GNUTLS session priority: %s\n", 311 | gnutls_strerror (ret)); 312 | goto error; 313 | } 314 | 315 | gnutls_session_set_ptr (s->session, (void *) s); 316 | 317 | ret = gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, s->creds); 318 | if (ret < 0) 319 | { 320 | errout (s, "Cannot set session GNUTL credentials: %s\n", 321 | gnutls_strerror (ret)); 322 | goto error; 323 | } 324 | 325 | if (isserver) 326 | { 327 | /* requests but does not check a client certificate */ 328 | gnutls_certificate_server_set_request (s->session, GNUTLS_CERT_REQUEST); 329 | } 330 | 331 | 332 | return s; 333 | 334 | error: 335 | if (s->session) 336 | gnutls_deinit (s->session); 337 | free (s); 338 | return NULL; 339 | } 340 | 341 | void 342 | tlssession_close (tlssession_t * s) 343 | { 344 | if (s->session) 345 | gnutls_deinit (s->session); 346 | free (s->hostname); 347 | free (s); 348 | } 349 | 350 | int 351 | tlssession_init () 352 | { 353 | return gnutls_global_init (); 354 | } 355 | 356 | 357 | int 358 | tlssession_mainloop (int cryptfd, int plainfd, tlssession_t * s) 359 | { 360 | fd_set readfds; 361 | fd_set writefds; 362 | int maxfd; 363 | int tls_wr_interrupted = 0; 364 | int plainEOF = FALSE; 365 | int cryptEOF = FALSE; 366 | int ret; 367 | 368 | buffer_t *plainToCrypt = bufNew (BUF_SIZE, BUF_HWM); 369 | buffer_t *cryptToPlain = bufNew (BUF_SIZE, BUF_HWM); 370 | 371 | if (socksetnonblock (cryptfd, 0) < 0) 372 | { 373 | errout (s, "Could not turn on blocking: %m"); 374 | goto error; 375 | } 376 | 377 | /* set it up to work with our FD */ 378 | gnutls_transport_set_ptr (s->session, 379 | (gnutls_transport_ptr_t) (intptr_t) cryptfd); 380 | 381 | 382 | /* Now do the handshake */ 383 | ret = gnutls_handshake (s->session); 384 | if (ret < 0) 385 | { 386 | errout (s, "TLS handshake failed: %s\n", gnutls_strerror (ret)); 387 | goto error; 388 | } 389 | 390 | if (socksetnonblock (cryptfd, 1) < 0) 391 | { 392 | errout (s, "Could not turn on non-blocking on crypt FD: %m"); 393 | goto error; 394 | } 395 | 396 | if (socksetnonblock (plainfd, 1) < 0) 397 | { 398 | errout (s, "Could not turn on non-blocking on plain FD: %m"); 399 | goto error; 400 | } 401 | 402 | maxfd = (plainfd > cryptfd) ? plainfd + 1 : cryptfd + 1; 403 | 404 | while ((!plainEOF || !cryptEOF) && !quit (s)) 405 | { 406 | struct timeval timeout; 407 | int result; 408 | int selecterrno; 409 | int wait = TRUE; 410 | 411 | FD_ZERO (&readfds); 412 | FD_ZERO (&writefds); 413 | 414 | size_t buffered = gnutls_record_check_pending (s->session); 415 | if (buffered) 416 | wait = FALSE; /* do not wait for select to return if we have buffered data */ 417 | 418 | if (plainEOF) 419 | { 420 | /* plain text end has closed, but me may still have 421 | * data yet to write to the crypt end */ 422 | if (bufIsEmpty (plainToCrypt) && !tls_wr_interrupted) 423 | { 424 | cryptEOF = TRUE; 425 | break; 426 | } 427 | } 428 | else 429 | { 430 | if (!bufIsEmpty (cryptToPlain)) 431 | FD_SET (plainfd, &writefds); 432 | if (!bufIsOverHWM (plainToCrypt)) 433 | FD_SET (plainfd, &readfds); 434 | } 435 | 436 | if (cryptEOF) 437 | { 438 | /* crypt end has closed, but me way still have data to 439 | * write from the crypt buffer */ 440 | if (bufIsEmpty (cryptToPlain) && !buffered) 441 | { 442 | plainEOF = TRUE; 443 | break; 444 | } 445 | } 446 | else 447 | { 448 | if (!bufIsEmpty (plainToCrypt) || tls_wr_interrupted) 449 | FD_SET (cryptfd, &writefds); 450 | if (!bufIsOverHWM (cryptToPlain)) 451 | FD_SET (cryptfd, &readfds); 452 | } 453 | 454 | /* Repeat select whilst EINTR happens */ 455 | do 456 | { 457 | timeout.tv_sec = wait ? 1 : 0; 458 | timeout.tv_usec = 0; 459 | result = select (maxfd, &readfds, &writefds, NULL, &timeout); 460 | 461 | selecterrno = errno; 462 | } 463 | while ((result == -1) && (selecterrno == EINTR) && !quit (s)); 464 | if (quit (s)) 465 | break; 466 | 467 | if (FD_ISSET (plainfd, &readfds)) 468 | { 469 | /* we can read at least one byte */ 470 | void *addr = NULL; 471 | /* get a span of characters to write to the 472 | * buffer. As the empty portion may wrap the end of the 473 | * circular buffer this might not be all we could read. 474 | */ 475 | ssize_t len = bufGetWriteSpan (plainToCrypt, &addr); 476 | if (len > 0) 477 | { 478 | ssize_t ret; 479 | do 480 | { 481 | ret = read (plainfd, addr, (size_t) len); 482 | } 483 | while ((ret < 0) && (errno == EINTR) && !quit (s)); 484 | if (quit (s)) 485 | break; 486 | if (ret < 0) 487 | { 488 | errout (s, "Error on read from plain socket: %m\n"); 489 | goto error; 490 | } 491 | if (ret == 0) 492 | { 493 | plainEOF = TRUE; 494 | } 495 | else 496 | { 497 | bufDoneWrite (plainToCrypt, ret); /* mark ret bytes as written to the buffer */ 498 | } 499 | } 500 | } 501 | 502 | if (FD_ISSET (plainfd, &writefds)) 503 | { 504 | /* we can write at least one byte */ 505 | void *addr = NULL; 506 | /* get a span of characters to read from the buffer 507 | * as the full portion may wrap the end of the circular buffer 508 | * this might not be all we have to write. 509 | */ 510 | ssize_t len = bufGetReadSpan (cryptToPlain, &addr); 511 | if (len > 0) 512 | { 513 | ssize_t ret; 514 | do 515 | { 516 | ret = write (plainfd, addr, (size_t) len); 517 | } 518 | while ((ret < 0) && (errno == EINTR) && !quit (s)); 519 | if (quit (s)) 520 | break; 521 | if (ret < 0) 522 | { 523 | errout (s, "Error on write to plain socket: %m\n"); 524 | goto error; 525 | } 526 | bufDoneRead (cryptToPlain, ret); /* mark ret bytes as read from the buffer */ 527 | } 528 | } 529 | 530 | if (FD_ISSET (cryptfd, &readfds) || buffered) 531 | { 532 | /* we can read at least one byte */ 533 | void *addr = NULL; 534 | /* get a span of characters to write to the 535 | * buffer. As the empty portion may wrap the end of the 536 | * circular buffer this might not be all we could read. 537 | */ 538 | ssize_t len = bufGetWriteSpan (cryptToPlain, &addr); 539 | if (len > 0) 540 | { 541 | ssize_t ret; 542 | do 543 | { 544 | ret = gnutls_record_recv (s->session, addr, (size_t) len); 545 | } 546 | while (ret == GNUTLS_E_INTERRUPTED && !quit (s)); 547 | /* do not loop on GNUTLS_E_AGAIN - this means we'd block so we'd loop for 548 | * ever 549 | */ 550 | if (quit (s)) 551 | break; 552 | if (ret < 0 && ret != GNUTLS_E_AGAIN) 553 | { 554 | errout (s, "Error on read from crypt socket: %s\n", 555 | gnutls_strerror (ret)); 556 | goto error; 557 | } 558 | if (ret == 0) 559 | { 560 | cryptEOF = TRUE; 561 | } 562 | else 563 | { 564 | bufDoneWrite (cryptToPlain, ret); /* mark ret bytes as written to the buffer */ 565 | } 566 | } 567 | } 568 | 569 | if (FD_ISSET (cryptfd, &writefds)) 570 | { 571 | /* we can write at least one byte */ 572 | void *addr = NULL; 573 | /* get a span of characters to read from the buffer 574 | * as the full portion may wrap the end of the circular buffer 575 | * this might not be all we have to write. 576 | */ 577 | ssize_t len = bufGetReadSpan (plainToCrypt, &addr); 578 | if (len > 0) 579 | { 580 | ssize_t ret; 581 | do 582 | { 583 | if (tls_wr_interrupted) 584 | { 585 | ret = gnutls_record_send (s->session, NULL, 0); 586 | } 587 | else 588 | { 589 | ret = gnutls_record_send (s->session, addr, len); 590 | } 591 | } 592 | while (ret == GNUTLS_E_INTERRUPTED && !quit (s)); 593 | if (quit (s)) 594 | break; 595 | if (ret == GNUTLS_E_AGAIN) 596 | { 597 | /* we need to call this again with NULL parameters 598 | * as it blocked 599 | */ 600 | tls_wr_interrupted = TRUE; 601 | } 602 | else if (ret < 0) 603 | { 604 | errout (s, "Error on write to crypto socket: %s\n", 605 | gnutls_strerror (ret)); 606 | goto error; 607 | } 608 | else 609 | { 610 | bufDoneRead (plainToCrypt, ret); /* mark ret bytes as read from the buffer */ 611 | } 612 | } 613 | } 614 | } 615 | 616 | ret = 0; 617 | goto freereturn; 618 | 619 | error: 620 | ret = -1; 621 | 622 | freereturn: 623 | gnutls_bye (s->session, GNUTLS_SHUT_RDWR); 624 | shutdown (plainfd, SHUT_RDWR); 625 | bufFree (plainToCrypt); 626 | bufFree (cryptToPlain); 627 | return ret; 628 | } 629 | --------------------------------------------------------------------------------