Switch from SCTP to TCP

Turns out SCTP doesn't work inside a container.
This commit is contained in:
Michael Spang 2009-11-01 14:43:15 -05:00
parent 11f432734c
commit d45fc419fa
7 changed files with 85 additions and 214 deletions

View File

@ -20,7 +20,7 @@ HOME_OBJECTS := homedir.o
HOME_LIBS := -lacl
HOME_PROGS := op-adduser
NET_OBJECTS := net.o gss.o ops.o
NET_LIBS := -lsctp $(shell krb5-config --libs gssapi)
NET_LIBS := $(shell krb5-config --libs gssapi)
NET_PROGS := ceod ceoc
PROTO_OBJECTS := ceo.pb-c.o
PROTO_LIBS := -lprotobuf-c

View File

@ -24,9 +24,8 @@ static void usage() {
static void send_gss_token(int sock, struct sockaddr *addr, socklen_t addrlen, gss_buffer_t token) {
OM_uint32 maj_stat, min_stat;
if (sctp_sendmsg(sock, token->value, token->length,
addr, addrlen, MSG_AUTH, 0, 0, 0, 0) < 0)
fatalpe("sctp_sendmsg");
if (ceo_send_message(sock, token->value, token->length, MSG_AUTH))
fatalpe("write");
maj_stat = gss_release_buffer(&min_stat, token);
if (maj_stat != GSS_S_COMPLETE)
@ -35,8 +34,8 @@ static void send_gss_token(int sock, struct sockaddr *addr, socklen_t addrlen, g
static void client_gss_auth(int sock, struct sockaddr *addr, socklen_t addrlen) {
gss_buffer_desc incoming_tok, outgoing_tok;
struct sctp_meta msg_meta;
struct strbuf msg = STRBUF_INIT;
uint32_t msgtype;
int complete;
complete = initial_client_token(&outgoing_tok);
@ -50,11 +49,11 @@ static void client_gss_auth(int sock, struct sockaddr *addr, socklen_t addrlen)
if (complete)
break;
if (!receive_one_message(sock, &msg_meta, &msg))
if (ceo_receive_message(sock, &msg, &msgtype))
fatal("connection closed during auth");
if (msg_meta.sinfo.sinfo_ppid != MSG_AUTH)
fatal("unexpected message type 0x%x", msg_meta.sinfo.sinfo_ppid);
if (msgtype != MSG_AUTH)
fatal("unexpected message type 0x%x", msgtype);
incoming_tok.value = msg.buf;
incoming_tok.length = msg.len;
@ -67,9 +66,9 @@ static void client_gss_auth(int sock, struct sockaddr *addr, socklen_t addrlen)
void run_remote(struct op *op, struct strbuf *in, struct strbuf *out) {
const char *hostname = op->hostname;
int sock = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in addr;
struct sctp_meta response_meta;
uint32_t msgtype;
struct strbuf in_cipher = STRBUF_INIT, out_cipher = STRBUF_INIT;
if (!in->len)
@ -80,40 +79,27 @@ void run_remote(struct op *op, struct strbuf *in, struct strbuf *out) {
addr.sin_port = htons(9987);
addr.sin_addr = op->addr;
struct sctp_event_subscribe events;
memset(&events, 0, sizeof(events));
events.sctp_data_io_event = 1;
events.sctp_association_event = 1;
events.sctp_address_event = 1;
events.sctp_send_failure_event = 1;
events.sctp_peer_error_event = 1;
events.sctp_shutdown_event = 1;
events.sctp_partial_delivery_event = 1;
events.sctp_adaptation_layer_event = 1;
if (setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)))
fatalpe("setsockopt");
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)))
fatalpe("connect");
client_acquire_creds("ceod", hostname);
client_gss_auth(sock, (sa *)&addr, sizeof(addr));
gss_encipher(in, &in_cipher);
if (sctp_sendmsg(sock, in_cipher.buf, in_cipher.len, (struct sockaddr *)&addr,
sizeof(addr), op->id, 0, 0, 0, 0) < 0)
fatalpe("sctp_sendmsg");
if (ceo_send_message(sock, in_cipher.buf, in_cipher.len, op->id))
fatalpe("write");
if (!receive_one_message(sock, &response_meta, &out_cipher))
if (ceo_receive_message(sock, &out_cipher, &msgtype))
fatal("no response received for op %s", op->name);
gss_decipher(&out_cipher, out);
if (response_meta.sinfo.sinfo_ppid != op->id)
fatal("wrong ppid from server: expected %d got %d", op->id, response_meta.sinfo.sinfo_ppid);
if (msgtype != op->id)
fatal("wrong message type from server: expected %d got %d", op->id, msgtype);
if (sctp_sendmsg(sock, NULL, 0, (struct sockaddr *)&addr,
sizeof(addr), 0, SCTP_EOF, 0, 0 ,0) < 0)
fatalpe("sctp_sendmsg");
if (close(sock))
fatalpe("close");
strbuf_release(&in_cipher);
strbuf_release(&out_cipher);

View File

@ -5,6 +5,3 @@ extern int fatal_signal;
/* dslave.c */
void slave_main(int sock, struct sockaddr *addr);
void setup_slave(void);
/* builtin-adduser.c */
extern void builtin_adduser(struct sctp_meta *in, struct sctp_meta *out);

View File

@ -138,7 +138,7 @@ static void accept_one_client(int server) {
}
static int master_main(void) {
int sock;
int sock, opt;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
@ -146,10 +146,14 @@ static int master_main(void) {
addr.sin_port = htons(9987);
addr.sin_addr.s_addr = INADDR_ANY;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
fatalpe("socket");
opt = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
fatalpe("setsockopt");
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
fatalpe("bind");

View File

@ -48,20 +48,6 @@ static void setup_slave_sigs(void) {
raise(fatal_signal);
}
static void setup_client(int client, struct sockaddr *addr) {
struct sctp_event_subscribe events;
memset(&events, 0, sizeof(events));
events.sctp_data_io_event = 1;
events.sctp_address_event = 1;
events.sctp_send_failure_event = 1;
events.sctp_peer_error_event = 1;
events.sctp_partial_delivery_event = 1;
events.sctp_adaptation_layer_event = 1;
if (setsockopt(client, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)))
fatalpe("setsockopt(SCTP_EVENTS)");
}
static void handle_auth_message(struct strbuf *in, struct strbuf *out) {
gss_buffer_desc incoming_tok, outgoing_tok;
OM_uint32 maj_stat, min_stat;
@ -113,19 +99,16 @@ static void handle_op_message(uint32_t in_type, struct strbuf *in, struct strbuf
strbuf_release(&out_plain);
}
static void handle_one_message(int sock, struct sctp_meta *in_meta, struct strbuf *in) {
static void handle_one_message(int sock, struct strbuf *in, uint32_t msgtype) {
struct strbuf out = STRBUF_INIT;
uint32_t ppid = in_meta->sinfo.sinfo_ppid;
if (ppid == MSG_AUTH)
if (msgtype == MSG_AUTH)
handle_auth_message(in, &out);
else
handle_op_message(ppid, in, &out);
handle_op_message(msgtype, in, &out);
if (out.len && sctp_sendmsg(sock, out.buf, out.len,
(sa *)&in_meta->from, in_meta->fromlen, ppid,
0, 0, 0, 0) < 0)
fatalpe("sctp_sendmsg");
if (out.len && ceo_send_message(sock, out.buf, out.len, msgtype))
fatalpe("write");
strbuf_release(&out);
}
@ -133,7 +116,7 @@ static void handle_one_message(int sock, struct sctp_meta *in_meta, struct strbu
void slave_main(int sock, struct sockaddr *addr) {
char addrstr[INET_ADDRSTRLEN];
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
struct sctp_meta msg_meta;
uint32_t msgtype;
struct strbuf msg = STRBUF_INIT;
if (addr->sa_family != AF_INET)
@ -145,12 +128,11 @@ void slave_main(int sock, struct sockaddr *addr) {
notice("accepted connection from %s", addrstr);
setup_slave_sigs();
setup_client(sock, addr);
while (!terminate) {
if (!receive_one_message(sock, &msg_meta, &msg))
if (ceo_receive_message(sock, &msg, &msgtype))
break;
handle_one_message(sock, &msg_meta, &msg);
handle_one_message(sock, &msg, msgtype);
}
notice("connection closed by peer %s", addrstr);

176
src/net.c
View File

@ -31,139 +31,65 @@ void free_fqdn(void) {
strbuf_release(&fqdn);
}
static size_t recv_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg, int *notification) {
size_t len = 0;
int flags = 0;
int bytes;
int ceo_send_message(int sock, void *buf, size_t len, uint32_t msgtype) {
uint32_t msgheader[2];
msgheader[0] = htonl(len);
msgheader[1] = htonl(msgtype);
if (full_write(sock, msgheader, sizeof(msgheader)) < 0)
fatalpe("write");
if (full_write(sock, buf, len) < 0)
fatalpe("write");
return 0;
}
int ceo_receive_message(int sock, struct strbuf *msg, uint32_t *msgtype) {
uint32_t msglen, received = 0;
uint32_t msgheader[2];
ssize_t bytes;
strbuf_reset(msg);
do {
msg_meta->fromlen = sizeof(msg_meta->from);
bytes = sctp_recvmsg(sock, msg->buf + len, strbuf_avail(msg) - len,
(sa *)&msg_meta->from, &msg_meta->fromlen, &msg_meta->sinfo, &flags);
while (received < sizeof(msgheader)) {
bytes = read(sock, msgheader, sizeof(msgheader) - received);
if (bytes < 0) {
if (errno == EAGAIN)
continue;
fatalpe("sctp_recvmsg");
fatalpe("read");
}
if (!bytes && !received)
return -1;
if (!bytes)
fatalpe("short header received");
received += bytes;
}
msglen = ntohl(msgheader[0]);
*msgtype = ntohl(msgheader[1]);
received = 0;
if (!msglen)
fatal("length is zero in message header");
if (msglen > MAX_MSGLEN)
fatal("length is huge in message header");
strbuf_grow(msg, msglen);
strbuf_setlen(msg, msglen);
while (received < msglen) {
bytes = read(sock, msg->buf + received, msglen - received);
if (bytes < 0) {
if (errno == EAGAIN)
continue;
fatalpe("read");
}
if (!bytes)
break;
len += bytes;
if (msg->len > MAX_MSGLEN)
fatal("oversized message received");
if (strbuf_avail(msg) < MSG_BUFINC)
strbuf_grow(msg, MSG_BUFINC);
} while (~flags & MSG_EOR);
if (!bytes && len)
fatalpe("EOF in the middle of a message");
*notification = flags & MSG_NOTIFICATION;
if (*notification) {
notification_dbg(msg->buf);
union sctp_notification *sn = (union sctp_notification *) msg->buf;
switch (sn->sn_header.sn_type) {
case SCTP_SHUTDOWN_EVENT:
fatal("connection shut down");
break;
case SCTP_ASSOC_CHANGE:
switch (sn->sn_assoc_change.sac_state) {
case SCTP_COMM_LOST:
fatal("connection lost");
break;
case SCTP_SHUTDOWN_COMP:
fatal("shutdown complete");
break;
case SCTP_CANT_STR_ASSOC:
fatal("connection failed (is ceod running?)");
break;
}
break;
}
fatal("short message received");
received += bytes;
}
strbuf_setlen(msg, len);
return len;
}
int receive_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg) {
int notification = 0;
do {
recv_one_message(sock, msg_meta, msg, &notification);
} while (notification);
return msg->len > 0;
}
void notification_dbg(char *notification) {
union sctp_notification *sn = (union sctp_notification *) notification;
char *extra;
switch (sn->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
extra = "unknown state";
switch (sn->sn_assoc_change.sac_state) {
case SCTP_COMM_UP: extra = "established"; break;
case SCTP_COMM_LOST: extra = "lost"; break;
case SCTP_RESTART: extra = "restarted"; break;
case SCTP_SHUTDOWN_COMP: extra = "completed shutdown"; break;
case SCTP_CANT_STR_ASSOC: extra = "cannot start"; break;
}
debug("association changed: association 0x%x %s", sn->sn_assoc_change.sac_assoc_id, extra);
break;
case SCTP_PEER_ADDR_CHANGE:
extra = "unknown state";
switch (sn->sn_paddr_change.spc_state) {
case SCTP_ADDR_AVAILABLE: extra = "unavailable"; break;
case SCTP_ADDR_UNREACHABLE: extra = "unreachable"; break;
case SCTP_ADDR_REMOVED: extra = "removed"; break;
case SCTP_ADDR_ADDED: extra = "added"; break;
case SCTP_ADDR_MADE_PRIM: extra = "made primary"; break;
#ifdef SCTP_ADDR_CONFIRMED
case SCTP_ADDR_CONFIRMED: extra = "confirmed"; break;
#endif
}
struct sockaddr_in *sa = (struct sockaddr_in *) &sn->sn_paddr_change.spc_aaddr;
char addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sa->sin_addr, addr, sizeof(addr));
debug("peer address change: remote address %s %s", addr, extra);
break;
case SCTP_REMOTE_ERROR:
debug("remote error: association=0x%x error=0x%x",
sn->sn_remote_error.sre_assoc_id,
sn->sn_remote_error.sre_error);
break;
case SCTP_SEND_FAILED:
debug("send failed: association=0x%x error=0x%x",
sn->sn_send_failed.ssf_assoc_id,
sn->sn_send_failed.ssf_error);
break;
case SCTP_ADAPTATION_INDICATION:
debug("adaptation indication: 0x%x",
sn->sn_adaptation_event.sai_adaptation_ind);
break;
case SCTP_PARTIAL_DELIVERY_EVENT:
extra = "unknown indication";
switch (sn->sn_pdapi_event.pdapi_indication) {
case SCTP_PARTIAL_DELIVERY_ABORTED:
extra = "partial delivery aborted";
break;
}
debug("partial delivery event: %s", extra);
break;
case SCTP_SHUTDOWN_EVENT:
debug("association 0x%x was shut down",
sn->sn_shutdown_event.sse_assoc_id);
break;
default:
debug("unknown sctp notification type 0x%x\n",
sn->sn_header.sn_type);
}
return 0;
}

View File

@ -1,47 +1,23 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <gssapi/gssapi.h>
#if ! defined(SCTP_ADDR_CONFIRMED) && defined(__linux__)
#define SCTP_ADDR_CONFIRMED 5
#endif
void notification_dbg(char *);
#ifdef SCTP_ADAPTION_LAYER
#define sctp_adaptation_layer_event sctp_adaption_layer_event
#define sn_adaptation_event sn_adaption_event
#define sai_adaptation_ind sai_adaption_ind
#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTION_INDICATION
#endif
typedef struct sockaddr sa;
extern struct strbuf fqdn;
extern void setup_fqdn(void);
extern void free_fqdn(void);
struct sctp_meta {
struct sockaddr_storage from;
socklen_t fromlen;
struct sctp_sndrcvinfo sinfo;
};
enum {
MSG_AUTH = 0x8000000,
MSG_EXPLODE = 0x8000001,
};
#ifdef MSG_ABORT
#define SCTP_ABORT MSG_ABORT
#define SCTP_EOF MSG_EOF
#endif
#define EKERB -2
#define ELDAP -3
#define EHOME -4
int receive_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg);
int ceo_receive_message(int sock, struct strbuf *msg, uint32_t *msgtype);
int ceo_send_message(int sock, void *msg, size_t len, uint32_t msgtype);