1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/* librist. Copyright © 2020 SipRadius LLC. All right reserved.
* Author: Sergio Ammirata, Ph.D. <sergio@ammirata.net>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <string.h>
#include <stdio.h>
#include "oob_shared.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
#include "socket-shim.h"
#ifdef USE_TUN
#include <librist/udpsocket.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#endif
static unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
void populate_ip_header(struct ipheader *ip, char *sourceip, char *destip, unsigned short api_id, unsigned short protocol)
{
ip->iph_verlen = 0x45;
ip->iph_tos = 0;
ip->iph_len = htons(sizeof(struct ipheader));
ip->iph_ident = htons(api_id);
ip->iph_flags = 0x0040;
ip->iph_ttl = 0x40;
ip->iph_protocol = protocol;
// The source IP address
unsigned int address = 0;
inet_pton(AF_INET, sourceip, &address);
ip->iph_sourceip = address;
// The destination IP address
inet_pton(AF_INET, destip, &address);
ip->iph_destip = address;
// make sure the checksum area is zero or the calculated checksum will be wrong
ip->iph_chksum = 0;
}
void populate_ipv4_rist_header(uint16_t address_family, uint8_t *recv_buf, ssize_t recv_bufsize, struct sockaddr * addr, socklen_t addrlen)
{
if (address_family == AF_INET6) {
// TODO: map ipv6 to ipv4
}
else {
// TODO
}
(void )address_family;
(void)recv_buf;
(void)recv_bufsize;
(void)addr;
(void)addrlen;
}
int oob_build_api_payload(char *buffer, char *sourceip, char *destip, char *message, int message_len)
{
// We populate a valid IP header here but we do not really use it for any type of routing
// We also populate a message that has the same information already present in the IP header but write it in text format
// This is only for demonstration purposes as we do not use the IP or the text message for anything on
// the receiving end or inside the library. However, this is a good method to create internal communication
// messages between peers. When designing your solution, just remember that in the OOB channel, there is no
// extra buffer delay and no packet recovery.
struct ipheader *ip = (struct ipheader *) buffer;
// unassigned protocol 252 used for API communication, api_id (54321 to identify this API message type)
populate_ip_header(ip, sourceip, destip, RIST_OOB_API_IP_IDENT_AUTH, RIST_OOB_API_IP_PROTOCOL);
memcpy(buffer + sizeof(struct ipheader), message, message_len);
int total_len = sizeof(struct ipheader) + message_len;
ip->iph_len = htons(total_len);
// Calculate the checksum for integrity since there is no packet recovery
ip->iph_chksum = csum((unsigned short *)buffer, total_len);
return total_len;
}
#ifdef USE_TUN
int oob_setup_tun_device(char *oobtun)
{
struct ifreq ifr;
int tun = 0;
int ret = 0;
memset(&ifr, 0, sizeof(ifr));
tun = open("/dev/net/tun", O_RDWR);
if (tun < 0) {
return -1;
}
ifr.ifr_flags = IFF_NO_PI | IFF_TUN;
strncpy(ifr.ifr_name, oobtun, IFNAMSIZ);
int r = ioctl(tun, TUNSETIFF, &ifr);
if (r < 0) {
close(tun);
return -2;
}
/* Get the flags that are set */
int skfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (skfd < 0 ) {
ret = -3;
goto fail;
}
if (ioctl(skfd, SIOCGIFFLAGS, (void*) &ifr)) {
ret = -4;
goto fail;
}
/* Set the flags that bring the device up */
ifr.ifr_flags |= ( IFF_UP | IFF_RUNNING );
if (ioctl(skfd, SIOCSIFFLAGS, (void*) &ifr)) {
ret = -5;
goto fail;
}
if (udpsocket_set_optimal_buffer_size(skfd) < 0) {
ret = -6;
goto fail;
}
if (udpsocket_set_optimal_buffer_send_size(skfd) < 0) {
ret = -7;
goto fail;
}
close(skfd);
return tun;
fail:
close(skfd);
close (tun);
return ret;
}
#endif
char *oob_process_api_message(int buffer_len, char *buffer, int *message_len)
{
struct ipheader *ip = (struct ipheader *) buffer;
int header_size = sizeof(struct ipheader);
// Check reported length vs buffer length
if (htons(buffer_len) != ip->iph_len) {
*message_len = RIST_OOB_ERROR_INVALID_LENGTH;
return NULL;
}
// Check for protocol type and only process API messages for now
if (ip->iph_protocol != RIST_OOB_API_IP_PROTOCOL) {
*message_len = RIST_OOB_ERROR_INVALID_PROTO;
return NULL;
}
// Check for only support API call
if (ip->iph_ident != htons(RIST_OOB_API_IP_IDENT_AUTH)) {
*message_len = RIST_OOB_ERROR_INVALID_IDENT;
return NULL;
}
// Move the buffer pointer and return the payload length
*message_len = buffer_len - header_size;
return buffer + header_size;
}
|