/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: Björn Påhlsson
  • Date: 2008-01-18 21:18:26 UTC
  • mto: This revision was merged to the branch mainline in revision 6.
  • Revision ID: belorn@legolas-20080118211826-5rbwo54l4bwim5x2
Client:
        [Working version in initrd for booting]
        Added #ifdef DEBUG statements through out the program
        Added support to keep bouth tcp and udp up at the same time
        Catching several more error return codes that was unchecked.
        Starts the Network interface during startup.
        Added support for entering password on console
        Added error handling, like looping until a password has been received.
        Added cleanup handling so console state is always restored
                
removed:
        Old server.cpp [see next version]
        Test certificates

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
                                // connect
4
4
#include <sys/socket.h>         // getaddrinfo, gai_strerror, socket, inet_pton
5
5
                                // connect
6
 
#include <unistd.h>             // close
 
6
#include <unistd.h>             // close, STDIN_FILENO, STDOUT_FILENO
7
7
#include <netdb.h>              // getaddrinfo, gai_strerror
8
8
#include <arpa/inet.h>          // inet_pton
9
9
#include <sys/select.h>         // select
10
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
11
14
}
12
15
 
13
 
#include <cstdio>               // fprintf
14
16
#include <cerrno>               // perror
15
17
#include <cstring>              // memset
 
18
#include <string>               // std::string, std::getline
 
19
#include <iostream>             // cin, cout, cerr
 
20
#include <ostream>              // <<
16
21
 
17
 
#define SOCKET_ERR(err,s) if(err<0) {perror(s);return(1);}
 
22
#define SOCKET_ERR(err,s) if(err<0) {perror(s); status = 1; goto quit;}
18
23
#define PORT 49001
19
 
#define CERTFILE "client-cert.pem"
20
 
#define KEYFILE "client-key.pem"
21
 
#define CAFILE "ca.pem"
 
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"
22
27
 
23
28
gnutls_certificate_credentials_t x509_cred;
24
29
 
26
31
initgnutls(){
27
32
  gnutls_session_t session;
28
33
 
 
34
#ifdef DEBUG
 
35
  std::cerr << "Initiate certificates\n";
 
36
#endif
 
37
 
29
38
  gnutls_global_init ();
30
39
 
31
40
  /* X509 stuff */
43
52
 
44
53
 
45
54
int main (){
46
 
  int sd, ret;
47
 
  char buffer[512];
 
55
  int udp_sd, tcp_sd, ret;
 
56
  char buffer[4096];
48
57
  struct sockaddr_in6 to;
49
58
  struct sockaddr_in6 from;
50
59
  gnutls_session_t session;
51
60
  fd_set rfds_orig;
52
61
  struct timeval timeout;
53
62
 
 
63
  struct termios t_old, t_new;
 
64
  int status = 0;
 
65
 
54
66
  session = initgnutls ();
55
67
 
56
 
  sd = socket(PF_INET6, SOCK_DGRAM, 0);
57
 
  SOCKET_ERR(sd,"socket");
58
 
 
 
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
  
59
79
  {
60
80
    int flag = 1;
61
 
    ret = setsockopt(sd, SOL_SOCKET, SO_BROADCAST, & flag, sizeof(flag));
 
81
    ret = setsockopt(udp_sd, SOL_SOCKET, SO_BROADCAST, & flag, sizeof(flag));
62
82
    SOCKET_ERR(ret,"setsockopt broadcast");
63
83
  }
64
84
 
65
 
  setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
 
85
  ret = setsockopt(udp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
66
86
  SOCKET_ERR(ret,"setsockopt bindtodevice");
67
87
 
68
88
  memset (&to, '\0', sizeof (to));
69
89
  to.sin6_family = AF_INET6;
70
90
  ret = inet_pton(AF_INET6, "ff02::1" , &to.sin6_addr);
71
 
  SOCKET_ERR(ret,"setsockopt bindtodevice");
 
91
  SOCKET_ERR(ret,"inet_pton");
72
92
  to.sin6_port = htons (PORT);  // Server Port number
73
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
    
74
106
  FD_ZERO(&rfds_orig);
75
 
  FD_SET(sd, &rfds_orig);
76
 
 
77
 
  timeout.tv_sec = 10;
78
 
  timeout.tv_usec = 0;
79
 
 
80
 
 
 
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
  
81
120
  for(;;){
82
 
    sendto(sd, "Marco", 5, 0, reinterpret_cast<const sockaddr*>(&to), sizeof(to));
83
 
 
84
 
    fd_set rfds = rfds_orig;
85
 
 
86
 
    ret = select(sd+1, &rfds, 0, 0, & timeout);
87
 
    SOCKET_ERR(sd,"select");
88
 
 
89
 
    if (ret){
90
 
      socklen_t from_len = sizeof(from);
91
 
      ret = recvfrom(sd,buffer,512,0, reinterpret_cast<sockaddr *>(& from),
92
 
                     & from_len);
93
 
      SOCKET_ERR(ret,"recv");
94
 
 
95
 
      if (strncmp(buffer,"Polo", 4) == 0){
96
 
        break;
97
 
      }
98
 
    }
 
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;
99
203
  }
100
 
 
101
 
  write(1,buffer,ret);
102
 
  write(1,"\n",1);
103
 
 
104
 
  //shutdown procedure
105
 
  close(sd);
106
 
 
107
 
  sleep(1);
108
 
 
109
 
  sd = socket(PF_INET6, SOCK_STREAM, 0);
110
 
  SOCKET_ERR(sd,"socket");
111
 
 
112
 
  setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
113
 
  SOCKET_ERR(ret,"setsockopt bindtodevice");
114
 
 
115
 
  memset(&to,0,sizeof(to));
116
 
  to.sin6_family = from.sin6_family;
117
 
  to.sin6_port   = from.sin6_port;
118
 
  to.sin6_addr   = from.sin6_addr;
119
 
  to.sin6_scope_id   = from.sin6_scope_id;
120
 
 
121
 
  ret = connect(sd,reinterpret_cast<struct sockaddr *>(&to),sizeof(to));
122
 
  SOCKET_ERR(ret,"connect");
123
 
 
124
 
  gnutls_transport_set_ptr (session, reinterpret_cast<gnutls_transport_ptr_t> (sd));
125
 
 
126
 
  ret = gnutls_handshake (session);
127
 
 
128
 
  if (ret < 0)
129
 
    {
130
 
      fprintf (stderr, "*** Handshake failed\n");
131
 
      gnutls_perror (ret);
132
 
      return 1;
133
 
    }
134
 
  printf ("- Handshake was completed\n");
135
 
 
136
 
  //message to be seent
137
 
  gnutls_record_send (session, "The secret message is \"squeamish ossifrage\"\n", 44);
138
 
 
139
 
  //shutdown procedure
140
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
141
 
  close(sd);
142
 
  gnutls_deinit (session);
143
 
  gnutls_certificate_free_credentials (x509_cred);
144
 
  gnutls_global_deinit ();
145
 
 
146
 
  close(sd);
147
 
 
148
 
  return 0;
 
204
  close(udp_sd);
 
205
 
 
206
 quit:
 
207
  tcsetattr (STDIN_FILENO, TCSAFLUSH, &t_old);
 
208
  return status;
149
209
}