indented dtls tutorial
parent
2629698168
commit
594248d9fd
|
@ -16,32 +16,32 @@ UDP header consists of 4 fields, each of which is 16 bits.
|
|||
Field 1: Contains information about the port from which the message originated.
|
||||
Field 2: Contains information about the destination port.
|
||||
Field 3: Defines the length in bytes of the UDP header and data. Allows for datagram of
|
||||
maximum size 65,535 bytes to be defined. If larger, set to 0. (IPv6 will allow larger).
|
||||
Field 4: Contains a Checksum for security purposes. Contains some checksum of the header and data.
|
||||
maximum size 65,535 bytes to be defined. If larger, set to 0. (IPv6 will allow larger).
|
||||
Field 4: Contains a Checksum for security purposes. Contains some checksum of the header and data.
|
||||
|
||||
CHECKSUM
|
||||
All 16 bit words are summed using “one's complement arithmetic”. The sum is then “one's complemented” and this is the value placed in the UDP checksum field.
|
||||
CHECKSUM
|
||||
All 16 bit words are summed using “one's complement arithmetic”. The sum is then “one's complemented” and this is the value placed in the UDP checksum field.
|
||||
|
||||
Figure 1.1 Check Sum Example
|
||||
EXAMPLE: you have two 16 bit words as follows :
|
||||
Figure 1.1 Check Sum Example
|
||||
EXAMPLE: you have two 16 bit words as follows :
|
||||
|
||||
ONE's COMPLEMENT OF WORD1: 1 0 0 1 1 1 1 0 0 1 1 0 0 0 1 0
|
||||
ONE's COMPLEMENT OF WORD2: 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 1
|
||||
---------------------------------
|
||||
SUM: 1 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1
|
||||
---------------------------------
|
||||
ONE's COMPLEMENT OF SUM: 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0
|
||||
ONE's COMPLEMENT OF WORD1: 1 0 0 1 1 1 1 0 0 1 1 0 0 0 1 0
|
||||
ONE's COMPLEMENT OF WORD2: 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 1
|
||||
---------------------------------
|
||||
SUM: 1 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1
|
||||
---------------------------------
|
||||
ONE's COMPLEMENT OF SUM: 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0
|
||||
|
||||
The final value would be placed in the Checksum Field.
|
||||
The final value would be placed in the Checksum Field.
|
||||
|
||||
|
||||
|
||||
|
||||
1.2. Creating a UDP/IP Server
|
||||
There are five initial steps to creating a UDP/IP Server.
|
||||
1.2. Creating a UDP/IP Server
|
||||
There are five initial steps to creating a UDP/IP Server.
|
||||
|
||||
1. Create the socket
|
||||
2. Identify the socket (IE give it a name)
|
||||
2. Identify the socket (IE give it a name)
|
||||
<Begin a loop>
|
||||
3. On the server wait for a message
|
||||
4. Send a response to the client once message is received
|
||||
|
@ -61,7 +61,7 @@ Field 3: Defines the length in bytes of the UDP header and data. Allows for data
|
|||
The domain can also be referred to as the address family. It is the communication domain in which the socket should be created. Below you will see some of the examples domains or address families that we could work with. At the end will be a description of what we will choose specifically for a UDP server.
|
||||
|
||||
AF_INET: Internet Protocol (IP)
|
||||
AF_INET6: IP version 6 (IPv6)
|
||||
AF_INET6: IP version 6 (IPv6)
|
||||
AF_UNIX: local channel, similar to pipes
|
||||
AF_ISO: “In Search Of” (ISO) protocols
|
||||
AF_NS: Xerox Network Systems protocols
|
||||
|
@ -90,24 +90,24 @@ Field 3: Defines the length in bytes of the UDP header and data. Allows for data
|
|||
perror("cannot create socket");
|
||||
return 0;
|
||||
}
|
||||
printf("created socket: descriptor=%d\n", sockfd);
|
||||
printf("created socket: descriptor=%d\n", sockfd);
|
||||
|
||||
|
||||
|
||||
|
||||
1.4. STEP 2: IDENTIFY/NAME THE SOCKET
|
||||
By naming the socket we are assigning a transport address to the socket (I.E. a port number in IP networking). This is more commonly referred to as “binding” an address. The bind system call is used to do this. In other words we are giving our server a unique address so that communication with our server can be established much like a person with a mailing address. They can receive communiques (letters) via their mailbox. Our server can do the same once it has a “bound” socket.
|
||||
1.4. STEP 2: IDENTIFY/NAME THE SOCKET
|
||||
By naming the socket we are assigning a transport address to the socket (I.E. a port number in IP networking). This is more commonly referred to as “binding” an address. The bind system call is used to do this. In other words we are giving our server a unique address so that communication with our server can be established much like a person with a mailing address. They can receive communiques (letters) via their mailbox. Our server can do the same once it has a “bound” socket.
|
||||
|
||||
The transport address is defined in the socket address structure. Since sockets can receive and send data using a myriad of communication interfaces, the interface is very general. Rather than accepting a port number as a parameter, it will look for a “sockaddr” (short for socket address)structure whose format is based off the address family we chose.
|
||||
The transport address is defined in the socket address structure. Since sockets can receive and send data using a myriad of communication interfaces, the interface is very general. Rather than accepting a port number as a parameter, it will look for a “sockaddr” (short for socket address)structure whose format is based off the address family we chose.
|
||||
|
||||
#include <sys/socket.h> contains the relevant “bind” call we will need. Since we already used it in STEP 1 we do not need to include it a second time.
|
||||
|
||||
Figure 1.4 Bind the Socket
|
||||
int
|
||||
bind(int socket, const struct sockaddr *address, socklen_t address_len);
|
||||
Figure 1.4 Bind the Socket
|
||||
int
|
||||
bind(int socket, const struct sockaddr *address, socklen_t address_len);
|
||||
|
||||
|
||||
The first parameter “socket” is the socket we created in STEP 1 (sockfd)
|
||||
The first parameter “socket” is the socket we created in STEP 1 (sockfd)
|
||||
The second parameter (sockaddr) will allow the operating system (OS) to read the first couple bytes that identify the address family. For UDP/IP networking we will use struct sockaddr_in, which is defined in the netinet/in.h system library.
|
||||
Defined:
|
||||
|
||||
|
@ -129,11 +129,11 @@ Figure 1.6
|
|||
|
||||
Before calling bind, we need to fill this struct. The three key parts we need to set are:
|
||||
|
||||
1. sin_family
|
||||
The address family we used in STEP 1 (AF_INET).
|
||||
1. sin_family
|
||||
The address family we used in STEP 1 (AF_INET).
|
||||
|
||||
2. sin_port
|
||||
The port number (transport address). This can either be explicitly declared, or you can allow the OS to assign one. Since we are creating a server, ideally we would want to explicitly declare a well known port so that clients know where to address their messages. However for this particular tutorial we will use the generic 11111 (five ones). This will be defined directly beneath the include section of our code.(figure 1.1.7)
|
||||
The port number (transport address). This can either be explicitly declared, or you can allow the OS to assign one. Since we are creating a server, ideally we would want to explicitly declare a well known port so that clients know where to address their messages. However for this particular tutorial we will use the generic 11111 (five ones). This will be defined directly beneath the include section of our code.(figure 1.1.7)
|
||||
|
||||
Figure 1.7
|
||||
#define SERV_PORT 11111
|
||||
|
@ -167,7 +167,7 @@ Before calling bind, we need to fill this struct. The three key parts we need to
|
|||
Defined:
|
||||
|
||||
Figure 1.8 “recvfrom”
|
||||
int recvfrom(int socket, void* restrict buffer, size_t length,
|
||||
int recvfrom(int socket, void* restrict buffer, size_t length,
|
||||
int socklen_t *restrict *src_len)
|
||||
|
||||
5.1 PARAMETERS DEFINED
|
||||
|
@ -209,7 +209,7 @@ recvlen = recvfrom(sockfd, buf, MSGLEN, 0, (struct sockaddr *)&cliaddr, &addrlen
|
|||
The server can use that address in sendto and send a message back to the recipient’s address.
|
||||
Defined:
|
||||
|
||||
Figure 1.11
|
||||
Figure 1.11
|
||||
sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&cliaddr, addrlen)
|
||||
|
||||
With this our UDP/IP server is now up and running. We can listen for client connections on a specific port, and we can acknowledge to the client that we have received the communications. Click link for a sample of completed code.
|
||||
|
@ -274,7 +274,7 @@ Figure 1.14
|
|||
int yourSocket = socket(domain, type, protocol);
|
||||
Example Code:
|
||||
|
||||
Figure 1.15
|
||||
Figure 1.15
|
||||
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
||||
err_sys("cannot create a socket.");
|
||||
This method checks for a socket creation error, a good idea when setting up any socket implementation. Include the socket header:
|
||||
|
@ -319,10 +319,10 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|||
We will begin by adding the following libraries to pull from.
|
||||
|
||||
Figure 2.1
|
||||
#include <cyassl/ssl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <cyassl/ssl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
1.2. Increase MSGLEN
|
||||
Next change the size of our MSGLEN to 4096 to be more universal. This step is unnecessary if you’re testing against the client.c located in cyassl/examples/client as it will only send a message of length 14 or so but why not be able to handle a little user input if we want to test against a friends client or something!
|
||||
|
@ -337,7 +337,7 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|||
1.3.3 Create ctx and sig_handler Method
|
||||
Now we declare a CYASSL_CTX pointer and call it “ctx” for simplicity, and declare a void sig_handler method that takes a constant integer as an argument.
|
||||
|
||||
1.3.4 Declare AwaitDGram()
|
||||
1.3.4 Declare AwaitDGram()
|
||||
Finally we will declare a method AwaitDGram(). We will break our client handling out of main() and handle those connection in our new method. This is in preparation for Chapter 3 where we will be handling multiple client connections simultaneously.Your variable section should now look something like Figure 2.2:
|
||||
|
||||
|
||||
|
@ -357,14 +357,14 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|||
Just below sig_handler insert the following lines:
|
||||
|
||||
Figure 2.3
|
||||
56 void AwaitDGram()
|
||||
56 void AwaitDGram()
|
||||
57 {
|
||||
58
|
||||
59 }
|
||||
|
||||
|
||||
|
||||
1.4.2 Move Variables from main()
|
||||
1.4.2 Move Variables from main()
|
||||
Literally cut and paste variable section from main() into our skeleton. Additionally add the variable “char ack”. This will be a reply message that we send to our clients. Ack is short for “Acknowledge”. So our clients have some sort of feedback letting them know that we received their communication successfully. See section 2.1.7.4 to see how ack is used in the code.
|
||||
|
||||
1.4.3 Remove un-needed Variables and Move all Declarations Together
|
||||
|
@ -372,7 +372,7 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|||
With this change we will also rename “addrlen” to “clilen” to remind us that this socklen_t is the length of the clients address and not to be confused with our socket’s address. We will no longer assign the length of “clilen” upon declaration either. That will be handled later in our program. Remove msgnum altogether. Take note: “recvlen” is being declared here however is not used until we have verified our client is encrypting with DTLS version 1.2. See sub-section 2.1.7.4 to see “recvlen” used in code. Our variable section should now look something like this:
|
||||
|
||||
Figure 2.4
|
||||
void AwaitDGram()
|
||||
void AwaitDGram()
|
||||
{
|
||||
int on = 1;
|
||||
int res = 1;
|
||||
|
@ -805,7 +805,7 @@ to:
|
|||
1.2.3.
|
||||
A char* object to print a message that session resume is testing.
|
||||
|
||||
Figure 4.1 (1.2.1-1.2.3 Example code:)
|
||||
Figure 4.1 (1.2.1-1.2.3 Example code:)
|
||||
CYASSL* sslResume = 0;
|
||||
CYASSL_SESSION* session = 0;
|
||||
char* srTest = "testing session resume";
|
||||
|
@ -819,7 +819,7 @@ to:
|
|||
2.3.
|
||||
Set up a new CyaSSL object for the resumption stage using sslResume.
|
||||
|
||||
Figure 4.2 (2.1-2.3 Example code:)
|
||||
Figure 4.2 (2.1-2.3 Example code:)
|
||||
CyaSSL_write(ssl, srTest, sizeof(srTest));
|
||||
session = CyaSSL_get_session(ssl);
|
||||
sslResume = CyaSSL_new(ctx);
|
||||
|
@ -861,14 +861,14 @@ to:
|
|||
Call CyaSSL_write with the same parameters as step A. only changing ssl to
|
||||
sslResume.
|
||||
|
||||
Figure 4.5 (2.7 - 2.12 Example Code:)
|
||||
Figure 4.5 (2.7 - 2.12 Example Code:)
|
||||
CyaSSL_set_fd(sslResume, sockfd);
|
||||
CyaSSL_set_session(sslResume, session);
|
||||
|
||||
if (CyaSSL_connect(sslResume) != SSL_SUCCESS)
|
||||
if (CyaSSL_connect(sslResume) != SSL_SUCCESS)
|
||||
err_sys("SSL_connect failed");
|
||||
|
||||
if(CyaSSL_session_reused(sslResume))
|
||||
if(CyaSSL_session_reused(sslResume))
|
||||
printf("reused session id\n");
|
||||
else
|
||||
printf("didn't reuse session id!!!\n");
|
||||
|
@ -909,7 +909,7 @@ fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
|||
NonBlockingDTLS_Connect(ssl);
|
||||
Replace:
|
||||
|
||||
Figure 4.9
|
||||
Figure 4.9
|
||||
if (CyaSSL_connect(sslResume) != SSL_SUCCESS)
|
||||
err_sys("SSL_connect failed");
|
||||
with:
|
||||
|
@ -965,20 +965,20 @@ Figure 5.1.1 non blocking server model
|
|||
2. Bind Socket
|
||||
3. Await DGram arrival
|
||||
|
||||
4. Set socket to nonblocking <--------------
|
||||
5. select |
|
||||
6. accept |
|
||||
7. Read Message |
|
||||
8. Reply to Message |
|
||||
9. Loop to step 4-----------------------------
|
||||
4. Set socket to nonblocking <--------------
|
||||
5. select |
|
||||
6. accept |
|
||||
7. Read Message |
|
||||
8. Reply to Message |
|
||||
9. Loop to step 4-----------------------------
|
||||
|
||||
|
||||
|
||||
1.2 udp_read_connect (int)
|
||||
1.2 udp_read_connect (int)
|
||||
We previously had this code in the body of AwaitDGram() however we broke it out to reduce the size of AwaitDGram() as well as to improve readability of the code. This is just our method to “watch” for datagrams to arrive.
|
||||
|
||||
Figure 5.2 watch for datagrams
|
||||
int udp_read_connect(int listenfd)
|
||||
int udp_read_connect(int listenfd)
|
||||
{
|
||||
int connfd;
|
||||
unsigned char b[1500];
|
||||
|
@ -1006,7 +1006,7 @@ Figure 5.1.1 non blocking server model
|
|||
Here we will see the variable “select_ret” dress up in different costumes. In order to get a costume we reference method “dtls_select()” to see how different costumes are picked by “select_ret” (see figure 5.5) Based on the costume “select_ret” is wearing we will make some decisions. This method is pulled in directly from the library test.h in the cyassl libraries and can be found in the following location: Starting from the root directory of cyassl type “cd cyassl” this is where test.h is located. Search for NonBlockingSSL_Accept to see this code in it’s original format. Figure 5.3 has some very minor edits to make it work with our example server.
|
||||
|
||||
Figure 5.3 NonBlockingSSL_Accept
|
||||
void NonBlockingSSL_Accept(CYASSL* ssl)
|
||||
void NonBlockingSSL_Accept(CYASSL* ssl)
|
||||
{
|
||||
int select_ret;
|
||||
int currTimeout = 1;
|
||||
|
@ -1056,7 +1056,7 @@ Figure 5.1.1 non blocking server model
|
|||
Again this method is pulled in from test.h however modified slightly to work with our server. (removed un-necessary #ifdefs). Here is where we use fcntl to set our socket to a non-blocking state.
|
||||
|
||||
Figure 5.4 set nonblocking
|
||||
235 static void dtls_set_nonblocking(int* listenfd)
|
||||
235 static void dtls_set_nonblocking(int* listenfd)
|
||||
236 {
|
||||
237 int flags = fcntl(*listenfd, F_GETFL, 0);
|
||||
238 if (flags < 0) {
|
||||
|
@ -1070,11 +1070,11 @@ Figure 5.1.1 non blocking server model
|
|||
246 }
|
||||
247 }
|
||||
|
||||
1.5 Select()
|
||||
1.5 Select()
|
||||
Again this is pulled from test.h and modified to work with our server. Here you see how “select_ret” from section 5.1.3 picks a costume to wear as a result of given conditions.
|
||||
|
||||
Figure 5.5 Picking a costume for select_ret
|
||||
249 static int dtls_select(int socketfd, int to_sec)
|
||||
249 static int dtls_select(int socketfd, int to_sec)
|
||||
250 {
|
||||
251 fd_set recvfds, errfds;
|
||||
252 int nfds = socketfd + 1;
|
||||
|
@ -1138,22 +1138,22 @@ Figure 5.1.1 non blocking server model
|
|||
buff[recvlen] = 0;
|
||||
printf("I heard this:\"%s\"\n", buff);
|
||||
}
|
||||
else {
|
||||
else {
|
||||
printf("Connection Timed Out.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (CyaSSL_write(ssl, ack, sizeof(ack)) < 0) {
|
||||
if (CyaSSL_write(ssl, ack, sizeof(ack)) < 0) {
|
||||
printf("Write error.\n");
|
||||
cleanup = 1;
|
||||
}
|
||||
printf("Reply sent:\"%s\"\n", ack);
|
||||
}
|
||||
printf("Reply sent:\"%s\"\n", ack);
|
||||
|
||||
/* free allocated memory */
|
||||
memset(buff, 0, sizeof(buff));
|
||||
CyaSSL_free(ssl);
|
||||
/* free allocated memory */
|
||||
memset(buff, 0, sizeof(buff));
|
||||
CyaSSL_free(ssl);
|
||||
|
||||
/* End: Reply to the Client */
|
||||
}
|
||||
/* End: Reply to the Client */
|
||||
}
|
||||
}
|
||||
|
||||
This concludes the tutorial section on making a dtls wrapped
|
||||
|
@ -1170,7 +1170,7 @@ enum {
|
|||
TEST_TIMEOUT,
|
||||
TEST_RECV_READY,
|
||||
TEST_ERROR_READY
|
||||
};
|
||||
};
|
||||
|
||||
2.3. Add a DTLS selection function
|
||||
This is similar to the tcp_select() function in CyaSSL. This function will also call
|
||||
|
@ -1207,7 +1207,7 @@ select():
|
|||
2.4. NonBlocking DTLS connect function:
|
||||
This function calls the connect function and checks for various errors within the connection attempts. We placed it before the DatagramClient() function:
|
||||
/*Connect using Nonblocking - DTLS version*/
|
||||
63 static void NonBlockingDTLS_Connect(CYASSL* ssl)
|
||||
63 static void NonBlockingDTLS_Connect(CYASSL* ssl)
|
||||
64 {
|
||||
65 int ret = CyaSSL_connect(ssl);
|
||||
66 int error = CyaSSL_get_error(ssl, 0);
|
||||
|
|
Loading…
Reference in New Issue