From c034e019f212727f6e2fbd6c824c7a965770ae28 Mon Sep 17 00:00:00 2001 From: pk910 Date: Fri, 18 Jul 2014 01:45:24 +0200 Subject: [PATCH] protocol parsers --- src/ircd_client.c | 10 -- src/ircd_client.h | 1 - src/ircd_parse.c | 290 +++++++++++++++++++++++++++++++++++++++++ src/ircd_parse.h | 33 +++++ src/ircd_sock.c | 17 ++- src/struct_servermsg.h | 64 +++++++++ 6 files changed, 399 insertions(+), 16 deletions(-) create mode 100644 src/ircd_parse.c create mode 100644 src/ircd_parse.h create mode 100644 src/struct_servermsg.h diff --git a/src/ircd_client.c b/src/ircd_client.c index 9fe8181..28d650b 100644 --- a/src/ircd_client.c +++ b/src/ircd_client.c @@ -54,13 +54,3 @@ void client_connected(struct Connection *conn) { void client_disconnected(struct Connection *conn) { } - -void client_recv(struct Connection *conn, char *line) { - if(conn->server) { - // Server protocol - } else { - - - - } -} diff --git a/src/ircd_client.h b/src/ircd_client.h index e0e0735..f113ae3 100644 --- a/src/ircd_client.h +++ b/src/ircd_client.h @@ -23,7 +23,6 @@ struct Connection; /* -- called from ircd_sock.c */ void client_connected(struct Connection *conn); void client_disconnected(struct Connection *conn); -void client_recv(struct Connection *conn, char *line); /* -- */ diff --git a/src/ircd_parse.c b/src/ircd_parse.c new file mode 100644 index 0000000..392459b --- /dev/null +++ b/src/ircd_parse.c @@ -0,0 +1,290 @@ +/* ircd_client.c - NextIRCd + * Copyright (C) 2012-2013 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ + +#include "tools.h" +#include "IOHandler/IOSockets.h" + +typedef int cmd_client_t(struct Client *client, char *argv[], int argc); +typedef int cmd_auth_t(struct Auth *auth, char *argv[], int argc); +typedef int cmd_server_t(struct Server *server, char *argv[], int argc); + +static struct ServerMsg parse_static_srvmsg; + +#define PARSE_CLIFLAG_OPONLY 0x01 + +//include all commands +#include "cmd_ping.h" + + +struct { + struct { + const char *client; + const char *server; + } tokens; + struct { + cmd_client_t *function; + unsigned int min_argc : 8; + unsigned int max_argc : 8; + unsigned int flags : 8; + } client; + struct { + cmd_auth_t *function; + unsigned int min_argc : 8; + unsigned int max_argc : 8; + unsigned int flags : 8; + } auth; + struct { + cmd_server_t *function; + unsigned int min_argc : 8; + unsigned int max_argc : 8; + unsigned int flags : 8; + } server; + +} parse_command_list { + {{"PING", "P"}, /* Ping Command */ + {NULL, 0, 1, 0}, /* Client */ + {NULL, 0, 1, 0}, /* Unauthed */ + {NULL, 0, 1, 0} /* Server */ + }, + + {{NULL, NULL},{NULL, 0, 0, 0},{NULL, 0, 0, 0},{NULL, 0, 0, 0}} +}; + +static char *parse_irc_token(char **data) { + //find next " " + int i; + char *token = *data; + for(i = 0; *data[i]; i++) { + if(*data[i] != ' ') { + *data[i] = '\0'; + *data += i+1; + break; + } + } + return token; +} + +static char **parse_irc_params(char *data, int *argc, int maxargs) { + if(maxargs == 0) { + *argc = 0; + return NULL; + } + char **argv = calloc(maxargs, sizeof(*argv)); + while(*data) { + //skip leading spaces + while (*line == ' ') + *line++ = 0; + if (*line == ':') { + //the rest is a single parameter + argv[*argc++] = line + 1; + break; + } + argv[*argc++] = line; + if (argc >= maxargs) + break; + while (*line != ' ' && *line) + line++; + } + return argv; +} + +/* Client Data Format +* +*/ +void parse_client_data(struct Client *client, char *data) { + char *token = parse_irc_token(&data); + int found = 0; + int i; + for(i = 0; (parse_command_list[i].tokens.client || parse_command_list[i].tokens.server); i++) { + if(stricmp(parse_command_list[i].tokens.client, token)) { + found = 1; + break; + } + } + if(found && !parse_command_list[i].client.function) { + // reply 462 You may not reregister + } else if(found) { + int argc; + char **argv = parse_irc_params(data, &argc, parse_command_list[i].client.max_argc); + if(argc < parse_command_list[i].client.min_argc) { + // reply 461 Not enough parameters + } else { + int ret = parse_command_list[i].client.function(client, argv, argc); + if(ret) { + // error occurred! + // do something? + } + } + free(argv); + } else { + // reply 421 Unknown command + } +} + +void parse_unauth_data(struct Auth *auth, char *data) { + char *token = parse_irc_token(&data); + int found = 0; + int i; + for(i = 0; (parse_command_list[i].tokens.client || parse_command_list[i].tokens.server); i++) { + if(stricmp(parse_command_list[i].tokens.client, token)) { + found = 1; + break; + } + } + if(found && !parse_command_list[i].auth.function) { + // reply 451 Register first. + } else if(found) { + int argc; + char **argv = parse_irc_params(data, &argc, parse_command_list[i].auth.max_argc); + if(argc < parse_command_list[i].auth.min_argc) { + // reply 461 Not enough parameters + } else { + int ret = parse_command_list[i].auth.function(auth, argv, argc); + if(ret) { + // error occurred! + // do something? + } + } + free(argv); + } else { + // reply 421 Unknown command + } +} + +/* Unicast Multicast Broadcast +* 4 Bytes 4 Bytes 4 Bytes +* 2 Bytes 2 Bytes 2 Bytes +* 1 Byte 1 Byte 1 Byte +* x Bytes x Bytes x Bytes +* " " 1 Byte " " 1 Byte " " 1 Byte +* 4 Bytes 1 Byte 1 Byte +* 4 Bytes +* 4 Bytes +* +*/ +void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer) { + struct ServerMsg *srvmsg = &parse_static_srvmsg; + unsigned char *buf = (unsigned char *)buffer->buffer; + unsigned int buflen, require_more = 0; + int i; + + while(buffer->bufpos >= 9 && !require_more) { //require at least 9 Bytes + srvmsg->source.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); + srvmsg->resolved_source = 0; + srvmsg->msglen = ((buf[4] << 8) | buf[5]); + srvmsg->msgflags = buf[6]; + srvmsg->msgtype = (buf[6] & SERVERMSG_TYPEMASK); + + if(buffer->bufpos < srvmsg->msglen) { + require_more = 1; + break; + } + + for(i = 0; buffer->bufpos > i+7; i++) { + if(buf[i+7] == ' ') { + if(i >= MAXSERVERTOKENLEN) + srvmsg->token[MAXSERVERTOKENLEN] = '\0'; + else + srvmsg->token[i] = '\0'; + break; + } + if(i >= MAXSERVERTOKENLEN) + continue; + srvmsg->token[i] = buf[i+7]; + } + if(buf[i+7] != ' ') { + require_more = 1; + break; + } + buf += i+8; + buflen = buffer->bufpos - (i+8); + + switch(srvmsg->msgtype) { + case SERVERMSG_TYPE_UNICAST: + if(buflen < 4) { + require_more = 1; + break; + } + srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap)); + srvmsg->destinations->dstcount = 1; + srvmsg->destinations->dst[0].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); + srvmsg->destinations->dst[0].destination.resolved_destination = 0; + break; + case SERVERMSG_TYPE_MULTICAST: + if(buflen < 5) { + require_more = 1; + break; + } + unsigned int srvcount = buf[0]; + buf++; + buflen--; + if(buflen < (srvcount * 4)) { + require_more = 1; + break; + } + srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap) + (sizeof(struct ServerMsgDestination) * (srvcount - 1))); + srvmsg->destinations->dstcount = srvcount; + for(i = 0; i < srvcount; i++) { + srvmsg->destinations->dst[i].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); + srvmsg->destinations->dst[i].destination.resolved_destination = 0; + buf += 4; + buflen -= 4; + } + break; + case SERVERMSG_TYPE_BROADCAST: + if(buflen == 0) { + require_more = 1; + break; + } + srvmsg->destinations = NULL; + srvmsg->msgttl = buf[0]; + buf++; + buflen--; + break; + default: + // PARSE ERROR + goto parse_server_data_finish; + } + + srvmsg->arglen = srvmsg->msglen - (buf - buffer->buffer); + srvmsg->args = buf; + + int found = 0; + for(i = 0; (parse_command_list[i].tokens.client || parse_command_list[i].tokens.server); i++) { + if(stricmp(parse_command_list[i].tokens.server, srvmsg->token)) { + found = 1; + break; + } + } + if(!found) + goto parse_server_data_finish; + + //exec command function + + + parse_server_data_finish: + if(srvmsg->destinations) + free(srvmsg->destinations); + + if(srvmsg->msglen > buffer->bufpos) { + memmove(buffer->buffer, buffer->buffer + srvmsg->msglen, srvmsg->msglen - buffer->bufpos); + buffer->bufpos -= srvmsg->msglen; + } else + srvmsg->bufpos = 0; + } +} + diff --git a/src/ircd_parse.h b/src/ircd_parse.h new file mode 100644 index 0000000..2360273 --- /dev/null +++ b/src/ircd_parse.h @@ -0,0 +1,33 @@ +/* ircd_parse.h - NextIRCd + * Copyright (C) 2012-2013 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ + +#ifndef _ircd_parse_h +#define _ircd_parse_h + +struct Client; +struct Auth; +struct Server; +struct IOSocketBuffer; + +/* -- called from ircd_client.c */ +void parse_client_data(struct Client *client, char *data); +void parse_unauth_data(struct Auth *auth, char *data); +void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer); +/* -- */ + + +#endif diff --git a/src/ircd_sock.c b/src/ircd_sock.c index 602282a..5e75008 100644 --- a/src/ircd_sock.c +++ b/src/ircd_sock.c @@ -18,6 +18,7 @@ #include "ircd_config.h" #include "ircd_sock.h" #include "ircd_client.h" +#include "ircd_parse.h" #include "struct_connection.h" #include "IOHandler/IOSockets.h" @@ -196,11 +197,12 @@ static IOSOCKET_CALLBACK(sockets_iohandler_callback) { break; case IOSOCKETEVENT_RECV: - if(connection->server) { - - } else { - client_recv(connection, event->data.recv_str); - } + if(!connection->authed) + parse_unauth_data(connection->data.auth, event->data.recv_str); + else if(connection->server) + parse_server_data(connection->data.server, event->data.recv_buf); + else + parse_client_data(connection->data.client, event->data.recv_str); break; default: @@ -212,3 +214,8 @@ void socket_send(struct Connection *conn, char *data, int len) { iosocket_send(conn->socket, data, len); } +void socket_set_server(struct Connection *conn) { + struct IOSocket *iosock = conn->socket; + iosock->parse_delimiter = 0; + conn->server = 1; +} diff --git a/src/struct_servermsg.h b/src/struct_servermsg.h new file mode 100644 index 0000000..09b1460 --- /dev/null +++ b/src/struct_servermsg.h @@ -0,0 +1,64 @@ +/* struct_servermsg.h - NextIRCd + * Copyright (C) 2012-2013 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ + +#ifndef _struct_servermsg_h +#define _struct_servermsg_h + +#define MAXSERVERTOKENLEN 5 + +#define SERVERMSG_TYPE_UNICAST 0x01 +#define SERVERMSG_TYPE_MULTICAST 0x02 +#define SERVERMSG_TYPE_BROADCAST 0x03 +#define SERVERMSG_TYPEMASK 0x07 +#define SERVERMSG_FLAG_ENCRYPTED 0x08 +#define SERVERMSG_FLAGMASK 0xF8 + +struct ServerMsgDestination { + union { + struct Server *server; + unsigned int srvnum; + } destination; + unsigned int resolved_destination : 1; +}; + +struct ServerMsgDstMap { + unsigned int dstcount : 8; + struct ServerMsgDestination dst[1]; +}; + +struct ServerMsg { + union { + struct Server *server; + unsigned int srvnum; + } source; + unsigned int resolved_source : 1; + + unsigned int msgtype : 3; + unsigned int msgflags : 8; + unsigned int msglen : 16; + unsigned int arglen : 16; + unsigned int msgttl : 8; + + char token[MAXSERVERTOKENLEN+1]; + + struct ServerMsgDstMap *destinations; + + + unsigned char *args; +}; + +#endif -- 2.20.1