/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:
 
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
}