SO_TIMESTAMP with OpenSSL? - c

When using a non-encrypted socket I'd use
int num bytes = recvmsg(sock, &msg, 0)
and then get the SO_TIMESTAMP info from the msg (see e.g. Linux recvmsg() not getting a software timestamp from socket and https://linux.die.net/man/2/recvmsg).
However, there doesn't seem to be a corresponding API for an SSL-encrypted socket, at least for OpenSSL. The only one I can see is
int SSL_read(SSL *ssl, void *buf, int num);
which obviously doesn't propagate the timestamp info.
Have people tried this before? I can see a few options,
fork/extend OpenSSL at the point where it reads from the raw socket and carry the data across
do a recvmsg(s, data, flags) explicitly and somehow pass that into an OpenSSL function for subsequent decoding.
use a different library?
I find surprisingly little info about this online.
Thanks!

Followed the comments suggestion by Steffen Ullrich (thank you) to make something work.
I ended up implementing a custom BIO along the lines of https://github.com/openssl/openssl/blob/master/crypto/bio/bio_sock.c but with recvmsg for the read path, and grabbing the SO_TIMESTAMP, which I subsequently stick in custom data.
I attach the BIO (SSL_set_bio) to my SSL object, and can retrieve the timestamp after a succesful SSL_read.
It was quite painful.

Related

Reading/writing encrypted data using file descriptors with OpenSSL

I'm not sure if this is a common way of interfacing with OpenSSL or not, but I can't really find any examples or references to trying to do it this way.
I have some applications that interfact with a number of things using file descriptors (nothing fancy here). This works great for plain text TCP sockets, for example: you can just read/write using normal standard library functions. I've used SSL_write and SSL_read before to read/write from encrypted connections, but I find this very clunky. The objective is handling I/O for things that could either be encrypted or not, and handling them in the same way. With the above, you have to pass around both SSL *ssl for encrypted connections and then a normal file descriptor for unencrypted connections, and depending on whether it's encrypted or not, use the right I/O functions, not all of which even have an SSL equivalent.
For example, the following macros illustrate this:
#ifdef HAVE_SSL_RECV
#define my_recv(ssl, fd, buf, len, flags) (ssl ? SSL_recv(ssl, buf, len, flags) : recv(fd, buf, len, flags)
#endif
#define my_read(ssl, fd, buf, len) (ssl ? SSL_read(ssl, buf, len) : read(fd, buf, len))
#define my_write(ssl, fd, buf, len) (ssl ? SSL_write(ssl, buf, len) : write(fd, buf, len))
What I would like to do is just have a file descriptor referring to the decrypted side of the SSL connection, such that anything written to or read from that file descriptor is encrypted/decrypted as you would expect with using SSL_read and SSL_write. What I'm on unclear on is if there is any builtin or standard way of doing this.
This related question (kind of but not quite) suggested BIO pairs: OpenSSL: perform en-/decryption without SSL_read() / SSL_write()
However, reading the man page for those (https://www.openssl.org/docs/manmaster/man3/BIO_s_bio.html), I don't think this is quite what I want, since BIO pairs do buffering and that's not what I need at all here.
Most similar types of interfaces that I've used provide a way to get a file descriptor that you can use in your program, and OpenSSL does have SSL_get_wfd and SSL_get_rfd, which I assumed would be what I was looking for, but it seems these are actually the raw socket file descriptor itself, exactly the same thing as the file descriptor passed to SSL_set_fd in the first place! (Confirmed by printing out all 3 file descriptors). So I'm not even sure what the point of these functions are in the first place, they don't provide any new information.
Obviously, I could use do this manually, by creating a pipe and then using one end of the pipe as my file descriptor for reading/writing and then spawn another thread to read/write from it and relay to the appropriate SSL functions, appropriately abstracting away that the connection is using TLS. But, is there a better or more standard way of doing this, and a way to avoid the overhead of additional threads for each SSL connection? (If not, that's fine, but I wanted to be sure before I went with that approach.)

Is it possible to write a packet, read by libpcap, with libnet? in c?

I'm trying to get libpcap to read a pcap file, get the user to select a packet and write that packet using libnet, in c.
I got the reading from file part done. Libpcap puts that packet into a const unsigned char. I have worked with libnet before, but never with libnet's advanced functions. I would just create the packet using libnet's build functions, then let them on their way. I realize there is a function, libnet_adv_write_link() that takes the libnet context, a pointer to a packet to inject(const uint8_t) and the size of the packet. I tried passing the 'packet' that I got from libpcap, and it compiled and executed without errors. However, I am not seeing anything in wireshark.
Would this be the right way to tackle this problem, or should I read from libpcap and build a separate packet with libnet, based on what libpcap read?
EDIT: I believe I somewhat solved the problem. I read the packet with libpcap. Put all the bytes after the 16th byte into another uchar and wrote that into the wire. using libnet_adv_write_raw_ipv4(), libnet initialized with LIBNET_RAW4_ADV. I believe, maybe because of the driver, I don't have much power over the ETH layer. so basically I just let it be written automatically this way, and the new uchar packet is just whatever is left after the ETH layer in the original packet. Works fine so far.
I'm the current libnet maintainer.
You should call libnet_write_link() to write a packet. If you aren't seeing it, its possible you haven't opened the correct device, that you lack permissions (you checked the return value of libnet_write_link I hope), and also possible that the packet injected was invalid.
If you don't need to build the packet, it sounds like you should be using pcap to send the packet, though, see http://www.tcpdump.org/manpages/pcap_inject.3pcap.html
Also, your statement "Libpcap puts that packet into a const unsigned char" is odd. A packet doesn't fit in a single char, what pcap does is, depending on the API, return pointers into the packet data. Its worth including a snippet of code showing how you get the packet from data, and how you pass it to libnet. Its possible you aren't using the pointers correctly.
If you are using libpcap, why not use libpcap to send the packet? No, it's not well known, but yes it does work. See the function pcap_sendpacket.
The packet libpcap returns is simply an array of bytes. Anything that takes an array of bytes (including the ethernet frame) should work. However, note that your OS and/or hardware may stop you from sending packets with incorrect or malformed source MAC addresses.

OpenSSL: perform en-/decryption without SSL_read() / SSL_write()

I've written an event-based networking library in C and now I want to add SSL/TLS support via OpenSSL. Instead of using SSL_read() and SSL_write(), I'd rather like to have OpenSSL only perform the encryption/decryption of outgoing/incoming data, letting me transmit/receive the data myself.
I'm new to SSL/TLS and OpenSSL, so:
Is there a way to have OpenSSL only perform encryption/decryption of char arrays?
Something like size_t SSL_encrypt(const char *buf_in, size_t size_in, char *buf_out) would be great.
Exactly what you've asked for isn't possible, because with TLS there isn't a 1-to-1 correspondence between sending something at the application layer and sending something on the network socket. Events like renegotiations mean that sometimes SSL needs to read data from the network in order to make progress sending data, and vice-versa.
However, you can still use OpenSSL to perform SSL but take care of the reading and writing from the network yourself. You do this by calling SSL_set_bio() on the SSL pointer instead of SSL_set_fd():
Use BIO_new_bio_pair() to create a connected BIO pair. One BIO will be read from and written to by the SSL routines, and the other BIO will be read from and written to by your application (allowing it to pass the data to the other end by whatever method it desires).
Use SSL_set_bio() on a new SSL object to set both the read and write BIO to one of the BIOs in the pair generated.
Use BIO_read() and BIO_write() on the other BIO in the pair to read and write the SSL protocol data.
Use SSL_accept(), SSL_connect(), SSL_read() and SSL_write() as normal on the SSL object.
(It's not clear what advantage this would give in your application, though: in this case you can't really do anything other than read and write exactly what OpenSSL passes you, so you might as well let it do the reading and writing too).

Sending a packet through a kernel module

I am trying to create a kernel module that will be able to send out modified packets from ones it receives through netfilter hooking. I'm using a code skeleton provided here. I am creating a raw socket inside the kernel simply using this code:
struct socket *sockptr;
sock_create(PF_INET, SOCK_RAW, IPPROTO_TCP, &sockptr);
The sendpacket function is called by this:
len = sendpacket(sockptr, dev, IPPROTO_TCP, duplicate, ntohs(dupiph->tot_len));
socketptr being the raw socket I created, dev being the net_device in passed to me by the hooking function, and duplicate being a modified copy of the original packet.
The return from the call to dev_queue_xmit indicates that the packet was transmitted successfully but I cannot see the packet on the wire. I have two questions: first, I would like to be able to better debug what is happening so any advice concerning that is much appreciated. Also, I am wondering if I am handling the socket creation properly or if there is some type of configuration I am missing. This is all very new to me so it very well could be that I am missing something silly.
It is unlikely that you need to modify the kernel to accomplish your task. Have you considered using tun or tap interface so you can do all of your work in user space? Here's a tutorial: http://backreference.org/2010/03/26/tuntap-interface-tutorial/

(How) Can I determine the socket family from the socket file descriptor

I am writing an API which includes IPC functions which send data to another process which may be local or on another host. I'd really like the send function to be as simple as:
int mySendFunc(myDataThing_t* thing, int sd);
without the caller having to know -- in the immediate context of the mySendFunc() call -- whether sd leads to a local or remote process. It seems to me that if I could so something like:
switch (socketFamily(sd)) {
case AF_UNIX:
case AF_LOCAL:
// Send without byteswapping
break;
default:
// Use htons() and htonl() on multi-byte values
break;
}
It has been suggested that I might implement socketFamily() as:
unsigned short socketFamily(int sd)
{
struct sockaddr sa;
size_t len;
getsockname(sd, &sa, &len);
return sa.sa_family;
}
But I'm a little concerned about the efficiency of getsockname() and wonder if I can afford to do it every time I send.
See getsockname(2). You then inspect the struct sockaddr for the family.
EDIT: As a side note, its sometimes useful to query info as well, in this case info libc sockets
EDIT:
You really can't know without looking it up every time. It can't be simply cached, as the socket number can be reused by closing and reopening it. I just looked into the glibc code and it seems getsockname is simply a syscall, which could be nasty performance-wise.
But my suggestion is to use some sort of object-oriented concepts. Make the user pass a pointer to a struct you had previously returned to him, i.e. have him register/open sockets with your API. Then you can cache whatever you want about that socket.
Why not always send in network byte order?
If you control the client and server code I have a different suggestion, which I've used successfully in the past.
Have the first four bytes of your message be a known integer value. The receiver can then inspect the first four bytes to see if it matches the known value. If it matches, then no byte swapping is needed.
This saves you from having to do byte swapping when both machines have the same endianness.

Resources