/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to server.cpp

  • Committer: Teddy Hogeborn
  • Date: 2024-11-17 18:43:11 UTC
  • Revision ID: teddy@recompile.se-20241117184311-ox25kvngy62h209g
Debian package: Avoid suggesting a C compiler unnecessarily

The list of suggested packages, meant to enable the "mandos" program
to find the correct value of SO_BINDTODEVICE by using a C compiler,
are not necessary when Python 3.3 or later is used, since it has the
SO_BINDTODEVICE constant defined in the "socket" module.  Also, Python
2.6 or older has the same constant in the old "IN" module.  Therefore,
we should suggest these Python versions as alternatives to a C
compiler, so that a C compiler is not installed unnecessarily.

debian/control (Package: mandos/Suggests): Add "python3 (>= 3.3)" and
"python (<= 2.6)" as alternatives to "libc6-dev | libc-dev" and
"c-compiler".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
extern "C" {
2
 
#include <sys/types.h> //socket, setsockopt, bind, listen, accept,
3
 
  // inet_ntop,
4
 
#include <sys/socket.h> //socket, setsockopt, bind, listen, accept,
5
 
  // inet_ntop
6
 
#include <sys/ioctl.h> //ioctl, sockaddr_ll, ifreq
7
 
#include <unistd.h> //write, close
8
 
#include <netinet/ip.h>         // sockaddr_in
9
 
#include <gnutls/gnutls.h>
10
 
#include <gnutls/x509.h>        // gnutls_x509_crt_init, gnutls_x509_crt_import, gnutls_x509_crt_get_dn
11
 
#include <arpa/inet.h>          // inet_ntop, htons
12
 
#include <net/if.h> //ifreq
13
 
}
14
 
 
15
 
#include <cstdio>
16
 
#include <cstring>
17
 
#include <cerrno>
18
 
#include <algorithm>            // std::max
19
 
#include <cstdlib>              // exit()
20
 
 
21
 
#define SOCKET_ERR(err,s) if(err<0) {perror(s);exit(1);}
22
 
 
23
 
#define PORT 49001
24
 
#define KEYFILE "key.pem"
25
 
#define CERTFILE "cert.pem"
26
 
#define CAFILE "ca.pem"
27
 
#define CRLFILE "crl.pem"
28
 
#define DH_BITS 1024
29
 
 
30
 
/* These are global */
31
 
gnutls_certificate_credentials_t x509_cred;
32
 
 
33
 
static gnutls_dh_params_t dh_params;
34
 
 
35
 
static int
36
 
generate_dh_params ()
37
 
{
38
 
 
39
 
  /* Generate Diffie Hellman parameters - for use with DHE
40
 
   * kx algorithms. These should be discarded and regenerated
41
 
   * once a day, once a week or once a month. Depending on the
42
 
   * security requirements.
43
 
   */
44
 
  gnutls_dh_params_init (&dh_params);
45
 
  gnutls_dh_params_generate2 (dh_params, DH_BITS);
46
 
 
47
 
  return 0;
48
 
}
49
 
 
50
 
gnutls_session_t
51
 
initialize_tls_session ()
52
 
{
53
 
  gnutls_session_t session;
54
 
 
55
 
  gnutls_global_init ();
56
 
 
57
 
  gnutls_certificate_allocate_credentials (&x509_cred);
58
 
  gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE,
59
 
                                          GNUTLS_X509_FMT_PEM);
60
 
  gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE,
61
 
                                        GNUTLS_X509_FMT_PEM);
62
 
  gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE,
63
 
                                        GNUTLS_X509_FMT_PEM);
64
 
 
65
 
  generate_dh_params ();
66
 
  gnutls_certificate_set_dh_params (x509_cred, dh_params);
67
 
 
68
 
  gnutls_init (&session, GNUTLS_SERVER);
69
 
  gnutls_set_default_priority (session);
70
 
  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
71
 
 
72
 
  // request client certificate if any.
73
 
 
74
 
  gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
75
 
  gnutls_dh_set_prime_bits (session, DH_BITS);
76
 
 
77
 
  return session;
78
 
}
79
 
 
80
 
 
81
 
void udpreply(int &sd){
82
 
  struct sockaddr_in6 sa_cli;
83
 
  int ret;
84
 
  char buffer[512];
85
 
 
86
 
  {
87
 
    socklen_t sa_cli_len = sizeof(sa_cli);
88
 
    ret = recvfrom(sd, buffer, 512,0,
89
 
                   reinterpret_cast<sockaddr *>(& sa_cli), & sa_cli_len);
90
 
    SOCKET_ERR (ret, "recvfrom");
91
 
  }
92
 
 
93
 
  if (strncmp(buffer,"Marco", 5) == 0){
94
 
    ret = sendto(sd, "Polo", 4, 0, reinterpret_cast<sockaddr *>(& sa_cli),
95
 
                 sizeof(sa_cli));
96
 
    SOCKET_ERR (ret, "sendto");
97
 
  }
98
 
 
99
 
}
100
 
 
101
 
void tcpreply(int sd, struct sockaddr_in6 sa_cli, gnutls_session_t session){
102
 
  int ret;
103
 
  unsigned int status;
104
 
  char buffer[512];
105
 
 
106
 
  printf ("- connection from %s, port %d\n",
107
 
          inet_ntop (AF_INET6, &sa_cli.sin6_addr, buffer,
108
 
                     sizeof (buffer)), ntohs (sa_cli.sin6_port));
109
 
 
110
 
  
111
 
  gnutls_transport_set_ptr (session, reinterpret_cast<gnutls_transport_ptr_t> (sd));
112
 
  
113
 
 
114
 
  ret = gnutls_handshake (session);
115
 
  if (ret < 0)
116
 
    {
117
 
      close (sd);
118
 
      gnutls_deinit (session);
119
 
      fprintf (stderr, "*** Handshake has failed (%s)\n\n",
120
 
               gnutls_strerror (ret));
121
 
      exit(1);
122
 
    }
123
 
  printf ("- Handshake was completed\n");
124
 
 
125
 
  //time to validate
126
 
 
127
 
    ret = gnutls_certificate_verify_peers2 (session, &status);
128
 
 
129
 
  if (ret < 0)
130
 
    {
131
 
      printf ("Verify failed\n");
132
 
      exit(1);
133
 
    }
134
 
 
135
 
  if (status & GNUTLS_CERT_INVALID)
136
 
    printf ("The certificate is not trusted.\n");
137
 
 
138
 
  if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
139
 
    printf ("The certificate hasn't got a known issuer.\n");
140
 
 
141
 
  if (status & GNUTLS_CERT_REVOKED)
142
 
    printf ("The certificate has been revoked.\n");
143
 
 
144
 
  if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509){
145
 
    printf("Recived certificate not X.509\n");
146
 
    exit(1);
147
 
  }
148
 
  {
149
 
    const gnutls_datum_t *cert_list;
150
 
    unsigned int cert_list_size = 0;
151
 
    gnutls_x509_crt_t cert;
152
 
    size_t size;
153
 
    char dn[128];
154
 
    
155
 
    cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
156
 
    
157
 
    printf ("Peer provided %d certificates.\n", cert_list_size);
158
 
    
159
 
    if (cert_list_size == 0){
160
 
      printf("No certificates recived\n"); //should never happen because verify_peers2 should fail if so
161
 
      exit(1);
162
 
    }
163
 
    
164
 
    gnutls_x509_crt_init (&cert);
165
 
    
166
 
    // XXX -Checking only first cert, might want to check them all
167
 
    gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
168
 
    
169
 
    size = sizeof (dn);
170
 
    gnutls_x509_crt_get_dn (cert, dn, &size);
171
 
    
172
 
    printf ("DN: %s\n", dn);
173
 
  }
174
 
  
175
 
  ret = gnutls_record_recv (session, buffer, sizeof(buffer));
176
 
 
177
 
  if (ret > 0)
178
 
    {
179
 
      write(1, buffer, ret);
180
 
    }
181
 
  else {
182
 
    fprintf (stderr, "\n*** Received corrupted "
183
 
             "data(%d). Closing the connection.\n\n", ret);
184
 
  }
185
 
  
186
 
  gnutls_bye (session, GNUTLS_SHUT_WR);
187
 
  close(sd);
188
 
  gnutls_deinit (session);
189
 
  gnutls_certificate_free_credentials (x509_cred);
190
 
  gnutls_global_deinit ();
191
 
}
192
 
 
193
 
 
194
 
int main (){
195
 
  int ret, err, udp_listen_sd, tcp_listen_sd;
196
 
  struct sockaddr_in6 sa_serv;
197
 
  struct sockaddr_in6 sa_cli;
198
 
 
199
 
  int optval = 1;
200
 
  socklen_t client_len;
201
 
 
202
 
  gnutls_session_t session;
203
 
 
204
 
  fd_set rfds_orig;
205
 
 
206
 
  session = initialize_tls_session ();
207
 
 
208
 
  //UDP socket creation
209
 
  udp_listen_sd = socket (PF_INET6, SOCK_DGRAM, 0);
210
 
  SOCKET_ERR (udp_listen_sd, "socket");
211
 
 
212
 
  memset (&sa_serv, '\0', sizeof (sa_serv));
213
 
  sa_serv.sin6_family = AF_INET6;
214
 
  sa_serv.sin6_addr = in6addr_any; //XXX only listen to link local?
215
 
  sa_serv.sin6_port = htons (PORT);     /* Server Port number */
216
 
 
217
 
  ret = setsockopt (udp_listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int));
218
 
  SOCKET_ERR(ret,"setsockopt reuseaddr");
219
 
 
220
 
  ret = setsockopt(udp_listen_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
221
 
  SOCKET_ERR(ret,"setsockopt bindtodevice");
222
 
 
223
 
  {
224
 
    int flag = 1;
225
 
    ret = setsockopt(udp_listen_sd, SOL_SOCKET, SO_BROADCAST, & flag, sizeof(flag));
226
 
    SOCKET_ERR(ret,"setsockopt broadcast");
227
 
  }
228
 
 
229
 
  err = bind (udp_listen_sd, reinterpret_cast<const sockaddr *> (& sa_serv),
230
 
              sizeof (sa_serv));
231
 
  SOCKET_ERR (err, "bind");
232
 
 
233
 
  //UDP socket creation done
234
 
 
235
 
 
236
 
  //TCP socket creation
237
 
 
238
 
  tcp_listen_sd = socket(PF_INET6, SOCK_STREAM, 0);
239
 
  SOCKET_ERR(tcp_listen_sd,"socket");
240
 
 
241
 
  setsockopt(tcp_listen_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
242
 
  SOCKET_ERR(ret,"setsockopt bindtodevice");
243
 
  
244
 
  ret = setsockopt (tcp_listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int));
245
 
  SOCKET_ERR(ret,"setsockopt reuseaddr");
246
 
 
247
 
  err = bind (tcp_listen_sd, reinterpret_cast<const sockaddr *> (& sa_serv),
248
 
              sizeof (sa_serv));
249
 
  SOCKET_ERR (err, "bind");
250
 
 
251
 
  err = listen (tcp_listen_sd, 1024);
252
 
  SOCKET_ERR (err, "listen");
253
 
 
254
 
  //TCP sockets creation done
255
 
 
256
 
  FD_ZERO(&rfds_orig);
257
 
  FD_SET(udp_listen_sd, &rfds_orig);
258
 
  FD_SET(tcp_listen_sd, &rfds_orig);
259
 
 
260
 
  printf ("Server ready. Listening to port '%d' on UDP and TCP.\n\n", PORT);
261
 
 
262
 
  for(;;){
263
 
    fd_set rfds = rfds_orig;
264
 
 
265
 
    ret = select(std::max(udp_listen_sd, tcp_listen_sd)+1, &rfds, 0, 0, 0);
266
 
    SOCKET_ERR(ret,"select");
267
 
 
268
 
    if (FD_ISSET(udp_listen_sd, &rfds)){
269
 
      udpreply(udp_listen_sd);
270
 
    }
271
 
 
272
 
    if (FD_ISSET(tcp_listen_sd, &rfds)){
273
 
 
274
 
      client_len = sizeof(sa_cli);
275
 
 
276
 
      int sd = accept (tcp_listen_sd,
277
 
               reinterpret_cast<struct sockaddr *> (& sa_cli),
278
 
               &client_len);
279
 
      SOCKET_ERR(sd,"accept"); //xxx not dieing when just connection abort      
280
 
      switch(fork()){
281
 
        case 0:
282
 
          tcpreply(sd, sa_cli, session);
283
 
          return 0;
284
 
          break;
285
 
      case -1:
286
 
        perror("fork");
287
 
        close(tcp_listen_sd);
288
 
        close(udp_listen_sd);
289
 
        return 1;
290
 
        break;
291
 
      default:
292
 
        break;
293
 
      }
294
 
    }
295
 
  }
296
 
 
297
 
  close(tcp_listen_sd);
298
 
  close(udp_listen_sd);
299
 
  return 0;
300
 
 
301
 
}