diff options
author | Alyssa Ross <hi@alyssa.is> | 2020-08-28 11:57:29 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2020-09-10 17:58:43 +0000 |
commit | ec8e077dee523f657f1445098def879f9559d66e (patch) | |
tree | 31727fd6ca372463879c3a850a5b8ffc6ac56b57 | |
download | ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.tar ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.tar.gz ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.tar.bz2 ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.tar.lz ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.tar.xz ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.tar.zst ucspi-vsock-ec8e077dee523f657f1445098def879f9559d66e.zip |
Initial commit
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | LICENSES/GPL-2.0-or-later.txt | 319 | ||||
-rw-r--r-- | Makefile | 31 | ||||
-rw-r--r-- | env.c | 35 | ||||
-rw-r--r-- | env.h | 7 | ||||
-rw-r--r-- | log.c | 55 | ||||
-rw-r--r-- | log.h | 27 | ||||
-rw-r--r-- | util.c | 37 | ||||
-rw-r--r-- | util.h | 12 | ||||
-rw-r--r-- | vsock.c | 72 | ||||
-rw-r--r-- | vsock.h | 12 | ||||
-rw-r--r-- | vsockclient.c | 88 | ||||
-rw-r--r-- | vsockserver.c | 126 |
13 files changed, 827 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a63eff4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +*.o +vsockclient +vsockserver diff --git a/LICENSES/GPL-2.0-or-later.txt b/LICENSES/GPL-2.0-or-later.txt new file mode 100644 index 0000000..1d80ac3 --- /dev/null +++ b/LICENSES/GPL-2.0-or-later.txt @@ -0,0 +1,319 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. + +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software +is covered by the GNU Lesser General Public License instead.) You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If +the software is modified by someone else and passed on, we want its recipients +to know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms +of this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or translated +into another language. (Hereinafter, translation is included without limitation +in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running the Program +is not restricted, and the output from the Program is covered only if its +contents constitute a work based on the Program (independent of having been +made by running the Program). Whether that is true depends on what the Program +does. + +1. You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence +of any warranty; and give any other recipients of the Program a copy of this +License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + +a) You must cause the modified files to carry prominent notices stating that +you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or +in part contains or is derived from the Program or any part thereof, to be +licensed as a whole at no charge to all third parties under the terms of this +License. + +c) If the modified program normally reads commands interactively when run, +you must cause it, when started running for such interactive use in the most +ordinary way, to print or display an announcement including an appropriate +copyright notice and a notice that there is no warranty (or else, saying that +you provide a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this License. +(Exception: if the Program itself is interactive but does not normally print +such an announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Program, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Program. + +In addition, mere aggregation of another work not based on the Program with +the Program (or with a work based on the Program) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under Section +2) in object code or executable form under the terms of Sections 1 and 2 above +provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, +which must be distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give +any third party, for a charge no more than your cost of physically performing +source distribution, a complete machine-readable copy of the corresponding +source code, to be distributed under the terms of Sections 1 and 2 above on +a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial +distribution and only if you received the program in object code or executable +form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy the +source code from the same place counts as distribution of the source code, +even though third parties are not compelled to copy the source along with +the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except +as expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses terminated +so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Program +(or any work based on the Program), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor +to copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of +the rights granted herein. You are not responsible for enforcing compliance +by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Program at all. For example, if a +patent license would not permit royalty-free redistribution of the Program +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system, which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose +any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing and reuse +of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + +<one line to give the program's name and an idea of what it does.> + +Copyright (C) <yyyy> <name of author> + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author Gnomovision comes +with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, +and you are welcome to redistribute it under certain conditions; type `show +c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than `show w' and `show c'; they could even be mouse-clicks +or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' +(which makes passes at compilers) written by James Hacker. + +<signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General +Public License does not permit incorporating your program into proprietary +programs. If your program is a subroutine library, you may consider it more +useful to permit linking proprietary applications with the library. If this +is what you want to do, use the GNU Lesser General Public License instead +of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b931c89 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +.POSIX: + +CFLAGS = -Wall -Wextra -O -g +INSTALL = install +INSTALL_PROGRAM = $(INSTALL) + +prefix = /usr/local +bindir = $(prefix)/bin + +all: vsockclient vsockserver +.PHONY: all + +install: vsockclient vsockserver + mkdir -p $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) vsockclient vsockserver $(DESTDIR)$(bindir) +.PHONY: install + +vsockclient: vsockclient.o env.o log.o util.o vsock.o + $(CC) $(LDFLAGS) -o vsockclient vsockclient.c env.o log.o util.o vsock.o $(LDLIBS) +vsockserver: vsockserver.o env.o log.o util.o vsock.o + $(CC) $(LDFLAGS) -o vsockserver vsockserver.c env.o log.o util.o vsock.o $(LDLIBS) + +vsockclient.o: env.h log.h util.h vsock.h +vsockserver.o: env.h log.h util.h vsock.h + +clean: + rm -f env.o log.o util.o vsock.o vsockclient vsockserver +.PHONY: clean diff --git a/env.c b/env.c new file mode 100644 index 0000000..4db8b2d --- /dev/null +++ b/env.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> + +#include "env.h" + +int vsetenvf(const char *name, int overwrite, const char *fmt, va_list args) +{ + char *s; + int r; + + if (vasprintf(&s, fmt, args) == -1) + return -1; + + r = setenv(name, s, overwrite); + + free(s); + return r; +} + +int setenvf(const char *name, int overwrite, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vsetenvf(name, overwrite, fmt, ap); + va_end(ap); + + return r; +} diff --git a/env.h b/env.h new file mode 100644 index 0000000..5429323 --- /dev/null +++ b/env.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#include <stdarg.h> + +int setenvf(const char *name, int overwrite, const char *fmt, ...); +int vsetenvf(const char *name, int overwrite, const char *fmt, va_list args); diff --git a/log.c b/log.c new file mode 100644 index 0000000..385d39f --- /dev/null +++ b/log.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include "log.h" + +#include <err.h> +#include <stdlib.h> + +enum verbosity verbosity = errors; + +void veloge(const char *fmt, va_list args) +{ + if (verbosity) + vwarn(fmt, args); +} + +void velog(const char *fmt, va_list args) +{ + if (verbosity) + vwarnx(fmt, args); +} + +void elog(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + velog(fmt, ap); + va_end(ap); +} + +void vilog(const char *fmt, va_list args) +{ + if (verbosity == all) + vwarnx(fmt, args); +} + +void ilog(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vilog(fmt, ap); + va_end(ap); +} + +void diee(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + veloge(fmt, ap); + va_end(ap); + + exit(eval); +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..a1b0c16 --- /dev/null +++ b/log.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#include <stdarg.h> + +enum verbosity { + nothing, + errors, + all, +}; + +extern enum verbosity verbosity; + +// Log an error message, followed by strerrno(errno), then exit with +// status eval. +void diee(int eval, const char *fmt, ...) __attribute__((noreturn)); + +// Log an error message. +void elog(const char *fmt, ...); +void velog(const char *fmt, va_list args); + +// Log an error message, followed by strerror(errno). +void veloge(const char *fmt, va_list args); + +// Log an informative message. +void ilog(const char *fmt, ...); +void vilog(const char *fmt, va_list args); diff --git a/util.c b/util.c new file mode 100644 index 0000000..634dca4 --- /dev/null +++ b/util.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include "util.h" + +#include <ctype.h> +#include <stdlib.h> + +int getu32(const char *s, uint32_t min, uint32_t max, uint32_t *out) +{ + unsigned long l; + + if (getul(s, min, max, &l) == -1) + return -1; + + *out = (uint32_t)l; + + return 0; +} + +int getul(const char *s, unsigned long min, unsigned long max, + unsigned long *out) +{ + char *endptr; + + if (!s || !isdigit(s[0]) || (s[0] == '0' && s[1])) + return -1; + + *out = strtoul(s, &endptr, 10); + + if (*endptr || *out < min || *out > max) + return -1; + + return 0; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..64347d1 --- /dev/null +++ b/util.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#include <stdint.h> + +// Strictly parse an integer from a string. The integer must span the +// whole string, not have any leading + or zeros, and be between min +// and max (inclusive). + +int getu32(const char *s, uint32_t min, uint32_t max, uint32_t *out); +int getul(const char *s, unsigned long min, unsigned long max, + unsigned long *out); diff --git a/vsock.c b/vsock.c new file mode 100644 index 0000000..3bcd8b3 --- /dev/null +++ b/vsock.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include "vsock.h" + +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <linux/vm_sockets.h> + +static void fill_sockaddr(struct sockaddr_vm *addr, uint32_t cid, uint32_t port) +{ + addr->svm_family = AF_VSOCK; + addr->svm_cid = cid; + addr->svm_port = port; +} + +int vsock_bind(int fd, uint32_t cid, uint32_t port) +{ + struct sockaddr_vm addr = { 0 }; + fill_sockaddr(&addr, cid, port); + + if (bind(fd, (struct sockaddr *)&addr, sizeof addr) == -1) + return -1; + + return 0; +} + +int vsock_accept(int sockfd, uint32_t *cid, uint32_t *port) +{ + struct sockaddr_vm addr = { 0 }; + socklen_t addr_size = sizeof addr; + + if (accept(sockfd, (struct sockaddr *)&addr, &addr_size) == -1) + return -1; + + *cid = addr.svm_cid; + *port = addr.svm_port; + + return 0; +} + +int vsock_connect(int fd, uint32_t cid, uint32_t port) +{ + struct sockaddr_vm addr = { 0 }; + fill_sockaddr(&addr, cid, port); + return connect(fd, (struct sockaddr *)&addr, sizeof addr); +} + +int vsock_open(uint32_t cid, uint32_t port) +{ + int fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (fd == -1) + return -1; + + return vsock_connect(fd, cid, port); +} + +int vsock_get_port(int fd, uint32_t *port) +{ + struct sockaddr_vm addr; + socklen_t addrlen = sizeof addr; + + if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) == -1) + return -1; + + *port = addr.svm_port; + + return 0; +} diff --git a/vsock.h b/vsock.h new file mode 100644 index 0000000..e7d66c9 --- /dev/null +++ b/vsock.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#include <stdint.h> + +int vsock_bind(int fd, uint32_t cid, uint32_t port); +int vsock_accept(int sockfd, uint32_t *cid, uint32_t *port); + +int vsock_connect(int fd, uint32_t cid, uint32_t port); +int vsock_open(uint32_t cid, uint32_t port); + +int vsock_get_port(int fd, uint32_t *port); diff --git a/vsockclient.c b/vsockclient.c new file mode 100644 index 0000000..ff8b7dc --- /dev/null +++ b/vsockclient.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> +#include <unistd.h> +#include <sys/socket.h> + +#include <linux/vm_sockets.h> + +#include "env.h" +#include "log.h" +#include "util.h" +#include "vsock.h" + +static void ex_usage(void) __attribute__((noreturn)); +static void ex_usage(void) +{ + if (verbosity) + fprintf(stderr, "Usage: %s [ -q | -Q | -v ] cid port prog...\n", + program_invocation_short_name); + exit(EX_USAGE); +} + +int main(int argc, char *argv[]) +{ + int opt, fd; + uint32_t rcid, rport; + + while ((opt = getopt(argc, argv, "+qQv")) != -1) { + switch (opt) { + case 'q': + verbosity = nothing; + break; + case 'Q': + verbosity = errors; + break; + case 'v': + verbosity = all; + break; + default: + ex_usage(); + } + } + + // Check there are enough positional arguments (two for the + // address and at least one to exec into). + if (optind > argc - 3) + ex_usage(); + + if (getu32(argv[optind++], 0, UINT32_MAX, &rcid)) + ex_usage(); + if (getu32(argv[optind++], 0, UINT32_MAX, &rport)) + ex_usage(); + + setenvf("VSOCKREMOTECID", 1, "%" PRIu32, rcid); + setenvf("VSOCKREMOTEPORT", 1, "%" PRIu32, rport); + + ilog("connecting to %" PRIu32 ":%" PRIu32 "...", rcid, rport); + + // Linux will sometimes randomly time out connections, even on + // the same host with no backlog, so retry a few times. + { + int i = 0; + do fd = vsock_open(rcid, rport); + while (i++ < 3 && fd == -1 && errno == ETIMEDOUT); + } + if (fd == -1) + diee(EX_UNAVAILABLE, + "connect to %" PRIu32 ":%" PRIu32 " failed", rcid, rport); + ilog("connected to %" PRIu32 ":%" PRIu32 "!", rcid, rport); + + // Set up the file descriptors to the well-known UCSPI numbers. + if (dup2(fd, 6) == -1) + diee(EX_OSERR, "dup2"); + if (dup2(fd, 7) == -1) + diee(EX_OSERR, "dup2"); + if (fd != 6 && fd != 7) + close(fd); + + execvp(argv[optind], &argv[optind]); + diee(EX_OSERR, "exec"); +} diff --git a/vsockserver.c b/vsockserver.c new file mode 100644 index 0000000..dd9a74a --- /dev/null +++ b/vsockserver.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sysexits.h> +#include <unistd.h> + +#include <linux/vm_sockets.h> + +#include "env.h" +#include "log.h" +#include "util.h" +#include "vsock.h" + +static void ex_usage(void) __attribute__((noreturn)); +static void ex_usage(void) +{ + if (verbosity) + fprintf(stderr, "Usage: %s [ -1 ] [ -q | -Q | -v ] cid port prog...\n", + program_invocation_short_name); + exit(EX_USAGE); +} + +int main(int argc, char *argv[]) +{ + bool notify = false; + int opt, conn; + pid_t child; + uint32_t lcid, lport, rcid, rport; + + while ((opt = getopt(argc, argv, "+1qQv")) != -1) { + switch (opt) { + case '1': + notify = true; + break; + case 'q': + verbosity = nothing; + break; + case 'Q': + verbosity = errors; + break; + case 'v': + verbosity = all; + break; + default: + ex_usage(); + } + } + + // Check there are enough positional arguments (two for the + // address and at least one to exec into). + if (optind > argc - 3) + ex_usage(); + + if (!strcmp(argv[optind], "-1")) + lcid = VMADDR_CID_ANY; + else if (getu32(argv[optind], 0, UINT32_MAX, &lcid)) + ex_usage(); + optind++; + + if (!strcmp(argv[optind], "-1")) + lport = VMADDR_PORT_ANY; + else if (getu32(argv[optind], 0, UINT32_MAX, &lport)) + ex_usage(); + optind++; + + int fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (fd == -1) + diee(EX_OSERR, "socket"); + + if (vsock_bind(fd, lcid, lport) == -1) + diee(EX_OSERR, "bind"); + + if (listen(fd, 40) == -1) + diee(EX_OSERR, "listen"); + + if (lport == VMADDR_PORT_ANY) + if (vsock_get_port(fd, &lport) == -1) + diee(EX_OSERR, "getsockname"); + + if (notify) { + printf("%" PRIu32 "\n", lport); + close(STDOUT_FILENO); + } + + setenvf("VSOCKLOCALCID", 1, "%" PRIu32, lcid); + setenvf("VSOCKLOCALPORT", 1, "%" PRIu32, lport); + + ilog("listening as %" PRIu32 " on port %" PRIu32, lcid, lport); + + while ((conn = vsock_accept(fd, &rcid, &rport)) != -1) { + setenvf("VSOCKREMOTECID", 1, "%" PRIu32, rcid); + setenvf("VSOCKREMOTEPORT", 1, "%" PRIu32, rport); + + ilog("connection from %" PRIu32 " port %" PRIu32, rcid, rport); + + switch (child = fork()) { + case -1: err(EX_OSERR, "fork"); + case 0: + if (dup2(conn, STDIN_FILENO) == -1) + err(EX_OSERR, "dup2"); + if (dup2(conn, STDOUT_FILENO) == -1) + err(EX_OSERR, "dup2"); + if (conn != 0 && conn != 1) + close(conn); + execvp(argv[optind], &argv[optind]); + err(EX_OSERR, "exec"); + } + + if (waitpid(child, NULL, 0) == -1) + err(EX_OSERR, "waitpid"); + + close(conn); + } + err(EX_OSERR, "accept"); +} |