vpnkit: Add a few files from vpnkit

From:
    https://github.com/moby/vpnkit
    commit 2ffc1dd8a84ea7359dd09b1f4b51bb728d4f46a0
    c/vpnkit-tap-vsockd/protocol.h
    c/vpnkit-tap-vsockd/protocol.c
This commit is contained in:
YAMAMOTO Takashi 2020-03-19 11:24:58 +09:00 committed by Xiang Xiao
parent 5d6d9eeb82
commit 261249cc99
2 changed files with 301 additions and 0 deletions

View File

@ -0,0 +1,224 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "log.h"
#include "protocol.h"
/* Version 0 of the protocol used this */
char expected_hello_old[5] = {'V', 'M', 'N', 'E', 'T'};
/* Version 1 and later of the protocol used this */
char expected_hello[5] = {'V', 'M', 'N', '3', 'T'};
int really_read(int fd, uint8_t *buffer, size_t total)
{
size_t remaining = total;
ssize_t n;
while (remaining > 0) {
n = read(fd, buffer, remaining);
if (n == 0) {
ERROR("EOF reading from socket: closing\n");
goto err;
}
if (n < 0) {
ERROR(
"Failure reading from socket: closing: %s",
strerror(errno));
goto err;
}
remaining -= (size_t) n;
buffer = buffer + n;
}
return 0;
err:
/*
* On error: stop reading from the socket and trigger a clean
* shutdown
*/
shutdown(fd, SHUT_RD);
return -1;
}
int really_write(int fd, uint8_t *buffer, size_t total)
{
size_t remaining = total;
ssize_t n;
while (remaining > 0) {
n = write(fd, buffer, remaining);
if (n == 0) {
ERROR("EOF writing to socket: closing");
goto err;
}
if (n < 0) {
ERROR(
"Failure writing to socket: closing: %s",
strerror(errno));
goto err;
}
remaining -= (size_t) n;
buffer = buffer + n;
}
return 0;
err:
/* On error: stop listening to the socket */
shutdown(fd, SHUT_WR);
return -1;
}
struct init_message *create_init_message()
{
struct init_message *m;
m = malloc(sizeof(struct init_message));
if (!m)
return NULL;
bzero(m, sizeof(struct init_message));
memcpy(&m->hello[0], &expected_hello[0], sizeof(m->hello));
m->version = CURRENT_VERSION;
memset(&m->commit[0], 0, sizeof(m->commit));
return m;
}
char *print_init_message(struct init_message *m)
{
char tmp[41];
memcpy(&tmp[0], &m->commit[0], 40);
tmp[40] = '\000';
char *buffer;
int n;
buffer = malloc(80);
if (!buffer)
return NULL;
n = snprintf(buffer, 80, "version %d, commit %s", m->version, tmp);
if (n < 0) {
perror("Failed to format init_message");
exit(1);
}
return buffer;
}
int read_init_message(int fd, struct init_message *ci)
{
int res;
bzero(ci, sizeof(struct init_message));
res = really_read(fd, (uint8_t *)&ci->hello[0], sizeof(ci->hello));
if (res == -1) {
ERROR("Failed to read hello from client");
return -1;
}
res = memcmp(&ci->hello[0],
&expected_hello_old[0], sizeof(expected_hello_old));
if (res == 0) {
ci->version = 0;
return 0;
}
res = memcmp(&ci->hello[0],
&expected_hello[0], sizeof(expected_hello));
if (res != 0) {
ERROR("Failed to read header magic from client");
return -1;
}
res = really_read(fd, (uint8_t *)&ci->version, sizeof(ci->version));
if (res == -1) {
ERROR("Failed to read header version from client");
return -1;
}
res = really_read(fd, (uint8_t *)&ci->commit[0], sizeof(ci->commit));
if (res == -1) {
ERROR("Failed to read header hash from client");
return -1;
}
return 0;
}
int write_init_message(int fd, struct init_message *ci)
{
int res;
res = really_write(fd, (uint8_t *)&ci->hello[0], sizeof(ci->hello));
if (res == -1) {
ERROR("Failed to write hello to client");
return -1;
}
if (ci->version > 0) {
res = really_write(fd, (uint8_t *)&ci->version,
sizeof(ci->version));
if (res == -1) {
ERROR("Failed to write version to client");
return -1;
}
res = really_write(fd, (uint8_t *)&ci->commit[0],
sizeof(ci->commit));
if (res == -1) {
ERROR("Failed to write header hash to client");
return -1;
}
}
return 0;
}
int read_vif_response(int fd, struct vif_info *vif)
{
struct msg_response msg;
if (really_read(fd, (uint8_t*)&msg, sizeof(msg)) == -1) {
ERROR("Client failed to read server response");
return -1;
}
switch (msg.response_type) {
case rt_vif:
memcpy((uint8_t*)vif, (uint8_t*)&msg.vif, sizeof(*vif));
return 0;
case rt_disconnect:
ERROR("Server disconnected: %*s", msg.disconnect.len, msg.disconnect.msg);
return -1;
default:
ERROR("Unknown response type from server");
return -1;
}
}
int write_command(int fd, enum command *c)
{
uint8_t command = *c;
if (really_write(fd, (uint8_t *)&command, sizeof(command)) == -1) {
ERROR("Failed to write command to client");
return -1;
}
return 0;
}
int write_ethernet_args(int fd, struct ethernet_args *args)
{
uint8_t buffer[40];
memset(&buffer[0], 0, sizeof(buffer));
memcpy(&buffer[0], (uint8_t *)&args->uuid_string[0], 36);
if (really_write(fd, (uint8_t *)&buffer, sizeof(buffer)) == -1) {
ERROR("Failed to write ethernet args to client");
return -1;
}
return 0;
}

View File

@ -0,0 +1,77 @@
#ifndef _VMNET_PROTOCOL_H_
#define _VMNET_PROTOCOL_H_
#include <errno.h>
#include <stdint.h>
/* Client -> Server init_message */
/* Server -> Client init_message */
struct init_message {
char hello[5];
uint8_t _padding[3];
uint32_t version;
char commit[40]; /* git sha of the compiled commit */
};
/*
* This should be bumped whenever we add something (like a feature or a
* bugfix) and we wish the UI to be able to detect when to trigger a
* reinstall.
*/
#define CURRENT_VERSION 22
extern struct init_message *create_init_message(void);
extern int read_init_message(int fd, struct init_message *ci);
extern int write_init_message(int fd, struct init_message *ci);
extern char *print_init_message(struct init_message *m);
/* Client -> Server command */
enum command {
ethernet = 1,
};
/* Server -> Client response */
enum response_type {
rt_vif = 1,
rt_disconnect = 2,
};
extern int write_command(int fd, enum command *c);
/* Client -> Server command arguments */
struct ethernet_args {
char uuid_string[36];
};
extern int write_ethernet_args(int fd, struct ethernet_args *args);
/* Server -> Client: details of a vif */
struct vif_info {
uint16_t mtu;
uint16_t max_packet_size;
uint8_t mac[6];
} __attribute__((packed));
/* Server -> Client: disconnect w/reason */
struct disconnect_reason {
uint8_t len;
char msg[256];
} __attribute__((packed));
struct msg_response {
uint8_t response_type;
union {
struct vif_info vif;
struct disconnect_reason disconnect;
};
} __attribute__((packed));
extern int read_vif_response(int fd, struct vif_info *vif);
extern char expected_hello[5];
extern char expected_hello_old[5];
extern int really_read(int fd, uint8_t *buffer, size_t total);
extern int really_write(int fd, uint8_t *buffer, size_t total);
#endif /* _VMNET_PROTOCOL_H_ */