/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 client.cpp

  • Committer: Teddy Hogeborn
  • Date: 2019-07-14 23:39:53 UTC
  • Revision ID: teddy@recompile.se-20190714233953-1zmsd3o062xloazt
Server bug fix: Allow restarts when using port= option

If the Mandos server is configured to use a specific TCP port to
listen to (by using the port= option in mandos.conf or the command
line --port option), that port becomes unusable for a time when the
Mandos server is restarted, making restarts fail.  Avoid this by, if a
port number is specified, using SO_REUSEADDR when binding the
listening TCP socket to a port number.

* mandos (IPv6_TCPServer.server_bind): Set self.allow_reuse_address if
                                       a port number is specified.

Reported-by: Juan Miguel Alcarria Herrera <juanmi@arco2000.es>

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
extern "C" {
2
 
#include <sys/types.h>          // getaddrinfo, gai_strerror, socket, inet_pton
3
 
                                // connect
4
 
#include <sys/socket.h>         // getaddrinfo, gai_strerror, socket, inet_pton
5
 
                                // connect
6
 
#include <unistd.h>             // close, STDIN_FILENO, STDOUT_FILENO
7
 
#include <netdb.h>              // getaddrinfo, gai_strerror
8
 
#include <arpa/inet.h>          // inet_pton
9
 
#include <sys/select.h>         // select
10
 
#include <gnutls/gnutls.h>
11
 
#include <sys/ioctl.h>          // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
12
 
#include <net/if.h>             // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
13
 
#include <termios.h>            // struct termios, tcsetattr, tcgetattr, TCSAFLUSH, ECHO
14
 
}
15
 
 
16
 
#include <cerrno>               // perror
17
 
#include <cstring>              // memset
18
 
#include <string>               // std::string, std::getline
19
 
#include <iostream>             // cin, cout, cerr
20
 
#include <ostream>              // <<
21
 
 
22
 
#define SOCKET_ERR(err,s) if(err<0) {perror(s); status = 1; goto quit;}
23
 
#define PORT 49001
24
 
#define CERTFILE "/conf/conf.d/cryptkeyreq/client-cert.pem"
25
 
#define KEYFILE "/conf/conf.d/cryptkeyreq/client-key.pem"
26
 
#define CAFILE "/conf/conf.d/cryptkeyreq/ca.pem"
27
 
 
28
 
gnutls_certificate_credentials_t x509_cred;
29
 
 
30
 
gnutls_session_t
31
 
initgnutls(){
32
 
  gnutls_session_t session;
33
 
 
34
 
#ifdef DEBUG
35
 
  std::cerr << "Initiate certificates\n";
36
 
#endif
37
 
 
38
 
  gnutls_global_init ();
39
 
 
40
 
  /* X509 stuff */
41
 
  gnutls_certificate_allocate_credentials (&x509_cred);
42
 
  gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, GNUTLS_X509_FMT_PEM);
43
 
  gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE,
44
 
                                        GNUTLS_X509_FMT_PEM);
45
 
 
46
 
  //Gnutls stuff
47
 
  gnutls_init (&session, GNUTLS_CLIENT);
48
 
  gnutls_set_default_priority (session);
49
 
  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
50
 
  return session;
51
 
}
52
 
 
53
 
 
54
 
int main (){
55
 
  int udp_sd, tcp_sd, ret;
56
 
  char buffer[4096];
57
 
  struct sockaddr_in6 to;
58
 
  struct sockaddr_in6 from;
59
 
  gnutls_session_t session;
60
 
  fd_set rfds_orig;
61
 
  struct timeval timeout;
62
 
 
63
 
  struct termios t_old, t_new;
64
 
  int status = 0;
65
 
 
66
 
  session = initgnutls ();
67
 
 
68
 
#ifdef DEBUG
69
 
  std::cerr << "Open ipv6 UDP\n";
70
 
#endif
71
 
 
72
 
  udp_sd = socket(PF_INET6, SOCK_DGRAM, 0);
73
 
  SOCKET_ERR(udp_sd,"socket");
74
 
  
75
 
#ifdef DEBUG
76
 
  std::cerr << "Open socket with socket nr: " << udp_sd << '\n';
77
 
#endif
78
 
  
79
 
  {
80
 
    int flag = 1;
81
 
    ret = setsockopt(udp_sd, SOL_SOCKET, SO_BROADCAST, & flag, sizeof(flag));
82
 
    SOCKET_ERR(ret,"setsockopt broadcast");
83
 
  }
84
 
 
85
 
  ret = setsockopt(udp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
86
 
  SOCKET_ERR(ret,"setsockopt bindtodevice");
87
 
 
88
 
  memset (&to, '\0', sizeof (to));
89
 
  to.sin6_family = AF_INET6;
90
 
  ret = inet_pton(AF_INET6, "ff02::1" , &to.sin6_addr);
91
 
  SOCKET_ERR(ret,"inet_pton");
92
 
  to.sin6_port = htons (PORT);  // Server Port number
93
 
 
94
 
  struct ifreq network;
95
 
 
96
 
  strcpy(network.ifr_name, "eth0");
97
 
 
98
 
  ret = ioctl(udp_sd, SIOCGIFFLAGS, &network);
99
 
  SOCKET_ERR(ret,"ioctl SIOCGIFFLAGS");
100
 
 
101
 
  network.ifr_flags |= IFF_UP;
102
 
 
103
 
  ret = ioctl(udp_sd, SIOCSIFFLAGS, &network);
104
 
  SOCKET_ERR(ret,"ioctl SIOCSIFFLAGS");
105
 
    
106
 
  FD_ZERO(&rfds_orig);
107
 
  FD_SET(udp_sd, &rfds_orig);
108
 
  FD_SET(STDIN_FILENO, &rfds_orig);
109
 
 
110
 
 
111
 
  if (tcgetattr (STDIN_FILENO, &t_old) != 0){
112
 
    return 1;
113
 
  }
114
 
  t_new = t_old;
115
 
  t_new.c_lflag &= ~ECHO;
116
 
  if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
117
 
    return 1;
118
 
  }
119
 
  
120
 
  for(;;){
121
 
    for(;;){
122
 
 
123
 
#ifdef DEBUG
124
 
      std::cerr << "Sending Marco on UDP\n";
125
 
#endif
126
 
      ret = sendto(udp_sd, "Marco", 5, 0, reinterpret_cast<const sockaddr*>(&to), sizeof(to));
127
 
      if (ret < 0){
128
 
        perror("sendto");
129
 
      }
130
 
      
131
 
      fd_set rfds = rfds_orig;
132
 
      timeout.tv_sec = 10;
133
 
      timeout.tv_usec = 0;
134
 
      
135
 
      std::cerr << "Password: ";
136
 
      
137
 
      ret = select(udp_sd+1, &rfds, 0, 0, & timeout);
138
 
      SOCKET_ERR(udp_sd,"select");
139
 
      
140
 
      if (ret){
141
 
        if (FD_ISSET(STDIN_FILENO, &rfds)){
142
 
          std::string buffer;
143
 
          std::getline(std::cin, buffer);
144
 
          std::cerr << '\n';
145
 
          std::cout << buffer;
146
 
          goto quit;
147
 
        }
148
 
        
149
 
        socklen_t from_len = sizeof(from);
150
 
        ret = recvfrom(udp_sd,buffer,512,0, reinterpret_cast<sockaddr *>(& from),
151
 
                       & from_len);
152
 
        SOCKET_ERR(ret,"recv");
153
 
        
154
 
        if (strncmp(buffer,"Polo", 4) == 0){
155
 
          break;
156
 
        }
157
 
      }
158
 
      std::cerr << '\r';
159
 
    }
160
 
    
161
 
    
162
 
    tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
163
 
    SOCKET_ERR(tcp_sd,"socket");
164
 
    
165
 
    setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
166
 
    SOCKET_ERR(ret,"setsockopt bindtodevice");
167
 
    
168
 
    memset(&to,0,sizeof(to));
169
 
    to.sin6_family = from.sin6_family;
170
 
    to.sin6_port   = from.sin6_port;
171
 
    to.sin6_addr   = from.sin6_addr;
172
 
    to.sin6_scope_id   = from.sin6_scope_id;
173
 
    
174
 
    ret = connect(tcp_sd,reinterpret_cast<struct sockaddr *>(&to),sizeof(to));
175
 
    if (ret < 0){
176
 
      perror("connect");
177
 
      continue;
178
 
    }
179
 
    
180
 
    gnutls_transport_set_ptr (session, reinterpret_cast<gnutls_transport_ptr_t> (tcp_sd));
181
 
    
182
 
    ret = gnutls_handshake (session);
183
 
    
184
 
    if (ret < 0)
185
 
      {
186
 
        std::cerr << "\n*** Handshake failed ***\n";
187
 
        gnutls_perror (ret);
188
 
        continue;
189
 
      }
190
 
    
191
 
    //retrive password
192
 
    ret = gnutls_record_recv (session, buffer, sizeof(buffer));
193
 
    
194
 
    write(STDOUT_FILENO,buffer,ret);
195
 
    
196
 
    //shutdown procedure
197
 
    gnutls_bye (session, GNUTLS_SHUT_RDWR);
198
 
    close(tcp_sd);
199
 
    gnutls_deinit (session);
200
 
    gnutls_certificate_free_credentials (x509_cred);
201
 
    gnutls_global_deinit ();
202
 
    break;
203
 
  }
204
 
  close(udp_sd);
205
 
 
206
 
 quit:
207
 
  tcsetattr (STDIN_FILENO, TCSAFLUSH, &t_old);
208
 
  return status;
209
 
}