int timeout = 900; /* ms */
int stop = 0;
+uint8_t aad[4] = { 0, 0, 0, 0 };
+
#define BUFMAX 4096
#define MAXPAYLOAD 1500
DECLARE_VERBOSE_LEVEL (ulvpn, INFO);
-typedef struct {
- uint8_t aad[4];
- int rxred;
- int rxblack;
- int txred;
- int txblack;
-} cm_t;
-
void sig_handler (int sig)
{
switch (sig) {
printf ("%s version %s\n", progname, version);
}
-int encrypt (uint8_t *buffer, int len, cm_t *cm)
+int pack_clear_data (uint8_t *buffer, int len, int maxlen)
{
/* create clear message */
CLEAR_DATA_t msg = {0};
msg.channel_id = 0;
msg.bypass_len = 0;
- memcpy (msg.aad + sizeof (msg.aad) - sizeof (cm->aad), cm->aad, sizeof (cm->aad));
+ memcpy (msg.aad + sizeof (msg.aad) - sizeof (aad), aad, sizeof (aad));
int npad = 16 - (len % 16);
if (len + npad > (int)sizeof (msg.data)) {
VERBOSE (ulvpn, WARNING, PRINTF ("too long payload (%d)\n", len));
VERBOSE (ulvpn, DEBUG, PRINTF ("padding %d byte%s\n", npad, (npad > 1) ? "s" : ""));
memcpy (msg.data, buffer, len);
msg.data[len + npad - 1] = npad;
- //memset (buffer, 0, len);
+ memset (buffer, 0, len);
msg.data_len = len + npad;
/* serialize message and send it */
- uint8_t out[MAXPAYLOAD] = {0};
- int out_len = serial_clear_data (&msg, out, sizeof (out));
- if (out_len < 0) {
+ len = serial_clear_data (&msg, buffer, maxlen);
+ if (len < 0) {
VERBOSE (ulvpn, WARNING, PRINTF ("error when serializing clear message\n"));
return 0;
}
- int seqtx = MOREP_Send (cm->txred, 0x00, out, out_len);
- VERBOSE (ulvpn, DEBUG, PRINTF ("send %d bytes to MOREP CM red\n", out_len));
- /* get encrypted message and check it */
- uint8_t in[MAXPAYLOAD] = {0};
- uint8_t msgtype = 0;
- int in_len = 0;
- int seqrx = MOREP_Receive_timeout (cm->rxblack, &msgtype, in, &in_len, timeout);
- VERBOSE (ulvpn, DEBUG, PRINTF ("received msg %d, seq %d/%d, length %d/%d bytes from MOREP CM black\n", msgtype, seqtx, seqrx, out_len, in_len));
- if ((msgtype != 0x01) || (in_len != out_len + 12 + 16) || ((seqcheck) && (seqtx != seqrx))) {
- VERBOSE (ulvpn, WARNING, PRINTF ("non-coherent encrypted message\n"));
- return 0;
+ return len;
+}
+
+#define CHECK_AND_STORE(size, statement) \
+ if ((!error) && (len + size < maxlen)) { \
+ statement; \
+ len += size; \
+ } else { \
+ error = 1; \
}
+
+int depack_encrypted_data (uint8_t *buffer, int len, int maxlen)
+{
+
+ /* get encrypted message and check it */
ENCRYPTED_DATA_t enc = {0};
- if (!deserial_encrypted_data (in, in_len, &enc)) {
+ if (deserial_encrypted_data (buffer, len, &enc)) {
VERBOSE (ulvpn, WARNING, PRINTF ("error when deserializing encrypted message\n"));
return 0;
}
+ memset (buffer, 0, len);
/* build output message */
len = 0;
- //buf[len++] = enc.channel_id;
- //check msg.bypass_len
- memcpy (buffer + len, cm->aad, sizeof (cm->aad));
- len += sizeof (cm->aad);
- memcpy (buffer + len, enc.iv, sizeof (enc.iv));
- len += sizeof (enc.iv);
- memcpy (buffer + len, enc.data, enc.data_len);
- len += enc.data_len;
-
- return len;
+ int error = 0;
+ //CHECK_AND_STORE (1, buf[len] = enc.channel_id);
+ //if ((!error) && (msg.bypass_len != 0)) { error = 1; }
+ CHECK_AND_STORE ((int)sizeof (aad), memcpy (buffer + len, enc.aad + sizeof (enc.aad) - sizeof (aad), sizeof (aad)));
+ CHECK_AND_STORE ((int)sizeof (enc.iv), memcpy (buffer + len, enc.iv, sizeof (enc.iv)));
+ CHECK_AND_STORE (enc.data_len, memcpy (buffer + len, enc.data, enc.data_len));
+
+ return (error) ? -1 : len;
}
-int decrypt (uint8_t *buffer, int len, cm_t *cm)
+#define CHECK_AND_PACK(size, statement) \
+ if ((!error) && (offset + size <= len)) { \
+ statement; \
+ offset += size; \
+ } else { \
+ error = 1; \
+ }
+
+int pack_encrypted_data (uint8_t *buffer, int len, int maxlen)
{
/* create encrypted message */
ENCRYPTED_DATA_t enc = {0};
- int i = 0;
- //if (i + 1 > len) {
- // VERBOSE (ulvpn, WARNING, PRINTF ("no channel id\n");
- // return 0;
- //}
- //enc.channel_id = buffer[i++];
+ int offset = 0;
+ int error = 0;
+ //CHECK_AND_PACK (1, enc.channel_id = buffer[offset]);
enc.bypass_len = 0;
- if (i + (int)sizeof (cm->aad) > len) {
- VERBOSE (ulvpn, ERROR, PRINTF ("incompleted aad\n"));
- return 0;
- }
- memcpy (enc.aad + sizeof (enc.aad) - sizeof (cm->aad), buffer + i, sizeof (cm->aad));
- i += sizeof (cm->aad);
- if (i + (int)sizeof (enc.iv) > len) {
- VERBOSE (ulvpn, ERROR, PRINTF ("incompleted iv\n"));
- return 0;
- }
- memcpy (enc.iv, buffer + i, sizeof (enc.iv));
- i += sizeof (enc.iv);
- if (len - i < 32) {
- VERBOSE (ulvpn, ERROR, PRINTF ("incompleted tag\n"));
- return 0;
- }
- if ((len - i) % 16 != 0) {
- VERBOSE (ulvpn, ERROR, PRINTF ("incompleted encrypted message\n"));
- return 0;
+ CHECK_AND_PACK ((int)sizeof (aad), memcpy (enc.aad + sizeof (enc.aad) - sizeof (aad), buffer + offset, sizeof (aad)));
+ CHECK_AND_PACK ((int)sizeof (enc.iv), memcpy (enc.iv, buffer + offset, sizeof (enc.iv)));
+ if ((!error) && ((len - offset >= 32) && ((len - offset) % 16 == 0))) {
+ memcpy (enc.data, buffer + offset, len - offset);
+ enc.data_len = len - offset;
+ } else {
+ return -1;
}
- memcpy (enc.data, buffer + i, len - i);
- enc.data_len = len - i;
+ memset (buffer, 0, len);
/* serialize message and send it */
- uint8_t out[MAXPAYLOAD] = {0};
- int out_len = serial_encrypted_data (&enc, out, sizeof (out));
- if (out_len < 0) {
+ len = serial_encrypted_data (&enc, buffer, maxlen);
+ if (len < 0) {
VERBOSE (ulvpn, WARNING, PRINTF ("error when serializing encrypted message\n"));
return 0;
}
- int seqtx = MOREP_Send (cm->txblack, 0x02, out, out_len);
- VERBOSE (ulvpn, DEBUG, PRINTF ("send %d bytes to MOREP CM black\n", out_len));
+
+ return len;
+}
+
+int depack_clear_data (uint8_t *buffer, int len, int maxlen)
+{
/* get clear message and check it */
- uint8_t in[MAXPAYLOAD] = {0};
- uint8_t msgtype = 0;
- int in_len = 0;
- int seqrx = MOREP_Receive_timeout (cm->rxred, &msgtype, in, &in_len, timeout);
- VERBOSE (ulvpn, DEBUG, PRINTF ("received msg %d, seq %d/%d, length %d/%d bytes from MOREP CM black\n", msgtype, seqtx, seqrx, out_len, in_len));
- VERBOSE (ulvpn, DEBUG, PRINTF ("received %d bytes from MOREP CM red\n", in_len));
- if ((msgtype != 0x03) || (in_len != out_len - 12 - 16) || ((seqcheck) && (seqtx != seqrx))) {
- VERBOSE (ulvpn, WARNING, PRINTF ("non-coherent decrypted message\n"));
- return 0;
- }
CLEAR_DATA_t msg = {0};
- if (!deserial_clear_data (in, in_len, &msg)) {
+ if (deserial_clear_data (buffer, len, &msg)) {
VERBOSE (ulvpn, WARNING, PRINTF ("error when deserializing decrypted message\n"));
return 0;
}
+ memset (buffer, 0, len);
/* build output message */
len = 0;
- //buf[len++] = enc.channel_id;
- //check msg.bypass_len
- int npad = in[in_len - 1];
- if ((npad > 16) || (msg.data_len < npad)) {
- VERBOSE (ulvpn, WARNING, PRINTF ("non-coherent padding (%d)\n", npad));
- return 0;
+ int error = 0;
+ CHECK_AND_STORE (msg.data_len, memcpy (buffer + len, msg.data, msg.data_len));
+ if (!error) {
+ int npad = msg.data[msg.data_len - 1];
+ if ((npad > 0) && (npad <= 16)) {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("unpadding %d byte%s\n", npad, (npad > 1) ? "s" : ""));
+ len -= npad;
+ } else {
+ error = 1;
+ }
}
- memcpy (buffer + len, enc.data, enc.data_len - npad);
- len += enc.data_len - npad;
- return len;
+ return (error) ? -1 : len;
}
int main (int argc, char **argv)
}
}
- /* init communication channel */
+ /* init udp and tun communication channels */
int tun_fd = MAPEC_Connect (devtun, loctun, remtun);
if (tun_fd < 0) {
VERBOSE (ulvpn, ERROR, PRINTF ("can't open communication for %s %s %s\n", devtun, loctun, remtun));
return -1;
}
- /* init crypto module */
- cm_t cm = {{0, 0, 0, 0}, -1, -1, -1, -1};
- int cmok = 0;
- if ((cmlocblack) && (cmremblack) && (cmlocred) && (cmremred)) {
- cmok = 1;
- if ((cm.rxblack = MOREP_Connect (cmlocblack)) < 0) {
- cmok = 0;
- }
- if ((cm.txblack = MOREP_Connect (cmremblack)) < 0) {
- cmok = 0;
- }
- if ((cm.rxred = MOREP_Connect (cmlocred)) < 0) {
- cmok = 0;
- }
- if ((cm.txred = MOREP_Connect (cmremred)) < 0) {
- cmok = 0;
- }
- }
+ /* init crypto module communication channels */
+ int rxblack_fd = (cmlocblack) ? MOREP_Connect (cmlocblack) : -1;
+ int txblack_fd = (cmremblack) ? MOREP_Connect (cmremblack) : -1;
+ int rxred_fd = (cmlocred) ? MOREP_Connect (cmlocred) : -1;
+ int txred_fd = (cmremred) ? MOREP_Connect (cmremred) : -1;
+ int cmok = (rxblack_fd > -1) && (txblack_fd > -1) && (rxred_fd > -1) && (txred_fd > -1);
if (!cmok) {
VERBOSE (ulvpn, INFO, PRINTF ("CM desactivated\n"));
}
+ VERBOSE (ulvpn, INFO, PRINTF ("fids: %d %d %d %d %d %d\n", tun_fd, udp_fd, rxblack_fd, txblack_fd, rxred_fd, txred_fd));
/* signals */
signal(SIGINT, sig_handler);
/* main loop */
int rc;
+ int seqrx = -1;
+ int seqtx = -1;
while (!stop) {
rc = 2;
fd_set readset;
- FD_ZERO (&readset);
+ int max_fd = 0;
FD_SET (tun_fd, &readset);
+ if (max_fd < tun_fd) {
+ max_fd = tun_fd;
+ }
FD_SET (udp_fd, &readset);
- int max_fd = ((tun_fd > udp_fd) ? tun_fd : udp_fd) + 1;
+ if (max_fd < udp_fd) {
+ max_fd = udp_fd;
+ }
+ if (cmok) {
+ FD_SET (rxblack_fd, &readset);
+ if (max_fd < rxblack_fd) {
+ max_fd = rxblack_fd;
+ }
+ FD_SET (rxred_fd, &readset);
+ if (max_fd < rxred_fd) {
+ max_fd = rxred_fd;
+ }
+ }
- if (-1 == select(max_fd, &readset, NULL, NULL, NULL)) {
+ if (-1 == select (max_fd + 1, &readset, NULL, NULL, NULL)) {
if (!stop) {
VERBOSE (ulvpn, ERROR, PRINTF ("select error\n"));
}
break;
}
- uint8_t buffer[MAXPAYLOAD] = {0};
-
if (FD_ISSET (tun_fd, &readset)) {
- int r = MAPEC_Receive (tun_fd, buffer, sizeof (buffer));
- if (r < 0) {
- // TODO: ignore some errno
- VERBOSE (ulvpn, ERROR, PRINTF ("error when receiving from tun\n"));
- //break;
+ uint8_t buffer[MAXPAYLOAD] = {0};
+ int rxlen = MAPEC_Receive (tun_fd, buffer, sizeof (buffer));
+ if (rxlen < 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when receiving from tun\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("received %d bytes from tun\n", rxlen));
+
+ if (cmok) {
+ int txlen = pack_clear_data (buffer, rxlen, sizeof (buffer));
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when packing clear data\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("packing %d bytes\n", txlen));
+ seqtx = MOREP_Send (txred_fd, 0x00, buffer, txlen);
+ if (seqtx < 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when sending to CM red\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("send %d bytes to CM red\n", txlen));
+ }
+ }
+ } else {
+ int txlen = MAPEC_Send (udp_fd, buffer, rxlen);
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when sending to udp\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("sent %d bytes to udp\n", txlen));
+ }
+ }
+ }
+
+ } else if (FD_ISSET (udp_fd, &readset)) {
+ uint8_t buffer[MAXPAYLOAD] = {0};
+ int rxlen = MAPEC_Receive (udp_fd, buffer, sizeof (buffer));
+ if (rxlen < 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when receiving from udp\n"));
} else {
- VERBOSE (ulvpn, DEBUG, PRINTF ("received from tun %d bytes\n", r));
+ VERBOSE (ulvpn, DEBUG, PRINTF ("received %d bytes from udp\n", rxlen));
if (cmok) {
- r = encrypt (buffer, r, &cm);
+ int txlen = pack_encrypted_data (buffer, rxlen, sizeof (buffer));
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when packing encrypted data\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("packing %d bytes\n", txlen));
+ seqtx = MOREP_Send (txblack_fd, 0x02, buffer, txlen);
+ if (seqtx < 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when sending to CM black\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("send %d bytes to CM black\n", txlen));
+ }
+ }
+ } else {
+ int txlen = MAPEC_Send (tun_fd, buffer, rxlen);
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when sending to tun\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("sent %d bytes to tun\n", txlen));
+ }
}
+ }
- if (r > 0) {
- r = MAPEC_Send (udp_fd, buffer, r);
+ } else if (FD_ISSET (rxblack_fd, &readset)) {
+ uint8_t buffer[MAXPAYLOAD] = {0};
+ uint8_t msgtype = -1;
+ int rxlen = 0;
+ seqrx = MOREP_Receive (rxblack_fd, &msgtype, buffer, &rxlen);
+
+ if (rxlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when receiving from CM black\n"));
+
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("received %d bytes from CM black\n", rxlen));
+
+ if (seqtx != seqrx) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("incoherent seqnum (%d/%d)\n", seqtx, seqrx));
}
- if (r <= 0) {
- // TODO: ignore some errno
- VERBOSE (ulvpn, ERROR, PRINTF ("error when sending to udp\n"));
- //break;
- } else if (r > 0) {
- VERBOSE (ulvpn, DEBUG, PRINTF ("sent to udp %d bytes\n", r));
+
+ if (msgtype == 0x01) {
+ int txlen = depack_encrypted_data (buffer, rxlen, sizeof (buffer));
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when depacking encrypted data\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("depacking %d bytes\n", txlen));
+ txlen = MAPEC_Send (udp_fd, buffer, txlen);
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when sending to udp\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("sent to udp %d bytes\n", txlen));
+ }
+ }
+
+
} else {
- VERBOSE (ulvpn, DEBUG, PRINTF ("nothing sent to udp\n"));
+ VERBOSE (ulvpn, WARNING, PRINTF ("can't process msgtype %d\n", msgtype));
}
}
- } else if (FD_ISSET (udp_fd, &readset)) {
- int r = MAPEC_Receive (udp_fd, buffer, sizeof (buffer));
- if (r < 0) {
- // TODO: ignore some errno
- VERBOSE (ulvpn, ERROR, PRINTF ("error when receiving from udp\n"));
- //break;
+ } else if (FD_ISSET (rxred_fd, &readset)) {
+ uint8_t buffer[MAXPAYLOAD] = {0};
+ uint8_t msgtype = -1;
+ int rxlen = 0;
+ seqrx = MOREP_Receive (rxred_fd, &msgtype, buffer, &rxlen);
+
+ if (rxlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when receiving from CM bred\n"));
+
} else {
- VERBOSE (ulvpn, DEBUG, PRINTF ("received from udp %d bytes\n", r));
+ VERBOSE (ulvpn, DEBUG, PRINTF ("received %d bytes from CM red\n", rxlen));
- if (cmok) {
- r = decrypt (buffer, r, &cm);
+ if (seqtx != seqrx) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("incoherent seqnum (%d/%d)\n", seqtx, seqrx));
}
- r = MAPEC_Send (tun_fd, buffer, r);
- if (r < 0) {
- // TODO: ignore some errno
- VERBOSE (ulvpn, ERROR, PRINTF ("error when sending to tun\n"));
- //break;
+ if (msgtype == 0x03) {
+ int txlen = depack_clear_data (buffer, rxlen, sizeof (buffer));
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when depacking clear data\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("depacking %d bytes\n", txlen));
+ txlen = MAPEC_Send (tun_fd, buffer, txlen);
+ if (txlen <= 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when sending to tun\n"));
+ } else {
+ VERBOSE (ulvpn, DEBUG, PRINTF ("sent to tun %d bytes\n", txlen));
+ }
+ }
+
+
} else {
- VERBOSE (ulvpn, DEBUG, PRINTF ("sent to tun %d bytes\n", r));
+ VERBOSE (ulvpn, WARNING, PRINTF ("can't process msgtype %d\n", msgtype));
}
}
+
}
rc = 0;
/* test: ulvpn.exe -v 5 -t udp://\*:1234 -u udp://localhost:1235 & pid1=$!; sleep 1; nc -ul 1235 > pcap & pid2=$!; sleep 1; echo TEST | nc -Nuq0 10.2.1.1 3000; sleep 1; kill -TERM $pid1 $pid2; strings pcap | grep -q TEST */
/* test: ulvpn.exe -v 5 -l tun://10.2.1.1 -r tun://10.2.0.0 -t udp://localhost:1234 -u udp://localhost:1235 & pid1=$!; sleep 1; nc -ul 3000 > text & pid2=$!; sleep 1; cat pcap | nc -4Nuq0 -p 1235 localhost 1234; sleep 1; kill -TERM $pid1 $pid2; test "$(cat text)" = TEST */
-
/* test: rm -f pcap text */
+
/* test: ip addr del dev eth0 10.1.0.1/24 && ip link del eth0 type dummy || echo no need to remove eth0 */
+/* test: ./test.sh ulvpn.exe */
+
/* vim: set ts=4 sw=4 si et: */