blob: 9c13ebdeaa915873b7d172e38de871444e3c63ea [file] [log] [blame]
Darin Petkov1c115202012-03-22 15:35:47 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/openvpn_management_server.h"
6
Darin Petkov78f63262012-03-26 01:30:24 +02007#include <netinet/in.h>
8
9#include <base/bind.h>
Darin Petkov1c115202012-03-22 15:35:47 +010010#include <base/logging.h>
Darin Petkov78f63262012-03-26 01:30:24 +020011#include <base/string_split.h>
12#include <base/string_util.h>
13#include <base/stringprintf.h>
14
15#include "shill/event_dispatcher.h"
Darin Petkov271fe522012-03-27 13:47:29 +020016#include "shill/openvpn_driver.h"
Darin Petkov78f63262012-03-26 01:30:24 +020017#include "shill/sockets.h"
18
19using base::Bind;
20using base::SplitString;
21using base::StringPrintf;
22using std::string;
23using std::vector;
Darin Petkov1c115202012-03-22 15:35:47 +010024
25namespace shill {
26
27OpenVPNManagementServer::OpenVPNManagementServer(OpenVPNDriver *driver)
Darin Petkov78f63262012-03-26 01:30:24 +020028 : driver_(driver),
29 weak_ptr_factory_(this),
30 ready_callback_(Bind(&OpenVPNManagementServer::OnReady,
31 weak_ptr_factory_.GetWeakPtr())),
32 input_callback_(Bind(&OpenVPNManagementServer::OnInput,
33 weak_ptr_factory_.GetWeakPtr())),
34 sockets_(NULL),
35 socket_(-1),
36 dispatcher_(NULL),
37 connected_socket_(-1) {}
Darin Petkov1c115202012-03-22 15:35:47 +010038
Darin Petkov78f63262012-03-26 01:30:24 +020039OpenVPNManagementServer::~OpenVPNManagementServer() {
40 Stop();
41}
Darin Petkov1c115202012-03-22 15:35:47 +010042
Darin Petkov78f63262012-03-26 01:30:24 +020043bool OpenVPNManagementServer::Start(EventDispatcher *dispatcher,
44 Sockets *sockets) {
Darin Petkov1c115202012-03-22 15:35:47 +010045 VLOG(2) << __func__;
Darin Petkov78f63262012-03-26 01:30:24 +020046 if (sockets_) {
47 return true;
48 }
49
Darin Petkov271fe522012-03-27 13:47:29 +020050 int socket = sockets->Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Darin Petkov78f63262012-03-26 01:30:24 +020051 if (socket < 0) {
52 PLOG(ERROR) << "Unable to create management server socket.";
53 return false;
54 }
55
56 struct sockaddr_in addr;
57 socklen_t addrlen = sizeof(addr);
58 memset(&addr, 0, sizeof(addr));
59 addr.sin_family = AF_INET;
60 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
61 if (sockets->Bind(
62 socket, reinterpret_cast<struct sockaddr *>(&addr), addrlen) < 0 ||
63 sockets->Listen(socket, 1) < 0 ||
64 sockets->GetSockName(
65 socket, reinterpret_cast<struct sockaddr *>(&addr), &addrlen) < 0) {
66 PLOG(ERROR) << "Socket setup failed.";
67 sockets->Close(socket);
68 return false;
69 }
70
71 VLOG(2) << "Listening socket: " << socket;
Darin Petkov271fe522012-03-27 13:47:29 +020072 sockets_ = sockets;
Darin Petkov78f63262012-03-26 01:30:24 +020073 socket_ = socket;
74 ready_handler_.reset(
75 dispatcher->CreateReadyHandler(
76 socket, IOHandler::kModeInput, ready_callback_));
77 dispatcher_ = dispatcher;
78 return true;
79}
80
81void OpenVPNManagementServer::Stop() {
82 VLOG(2) << __func__;
83 if (!sockets_) {
84 return;
85 }
86 input_handler_.reset();
87 if (connected_socket_ >= 0) {
88 sockets_->Close(connected_socket_);
89 connected_socket_ = -1;
90 }
91 dispatcher_ = NULL;
92 ready_handler_.reset();
93 if (socket_ >= 0) {
94 sockets_->Close(socket_);
95 socket_ = -1;
96 }
97 sockets_ = NULL;
98}
99
100void OpenVPNManagementServer::OnReady(int fd) {
101 VLOG(2) << __func__ << "(" << fd << ")";
102 connected_socket_ = sockets_->Accept(fd, NULL, NULL);
103 if (connected_socket_ < 0) {
104 PLOG(ERROR) << "Connected socket accept failed.";
105 return;
106 }
107 ready_handler_.reset();
108 input_handler_.reset(
109 dispatcher_->CreateInputHandler(connected_socket_, input_callback_));
110 SendState("on");
111}
112
113void OpenVPNManagementServer::OnInput(InputData *data) {
114 VLOG(2) << __func__ << "(" << data->len << ")";
115 vector<string> messages;
116 SplitString(
117 string(reinterpret_cast<char *>(data->buf), data->len), '\n', &messages);
118 for (vector<string>::const_iterator it = messages.begin();
119 it != messages.end(); ++it) {
120 ProcessMessage(*it);
121 }
122}
123
124void OpenVPNManagementServer::ProcessMessage(const string &message) {
125 VLOG(2) << __func__ << "(" << message << ")";
Darin Petkov271fe522012-03-27 13:47:29 +0200126 LOG_IF(WARNING,
127 !ProcessInfoMessage(message) &&
128 !ProcessNeedPasswordMessage(message) &&
129 !ProcessFailedPasswordMessage(message) &&
130 !ProcessStateMessage(message))
131 << "OpenVPN management message ignored: " << message;
132}
133
134bool OpenVPNManagementServer::ProcessInfoMessage(const string &message) {
135 return StartsWithASCII(message, ">INFO:", true);
136}
137
138bool OpenVPNManagementServer::ProcessNeedPasswordMessage(
139 const string &message) {
140 if (!StartsWithASCII(message, ">PASSWORD:Need ", true)) {
141 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200142 }
Darin Petkov271fe522012-03-27 13:47:29 +0200143 NOTIMPLEMENTED();
144 return true;
145}
146
147bool OpenVPNManagementServer::ProcessFailedPasswordMessage(
148 const string &message) {
149 if (!StartsWithASCII(message, ">PASSWORD:Verification Failed:", true)) {
150 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200151 }
Darin Petkov271fe522012-03-27 13:47:29 +0200152 NOTIMPLEMENTED();
153 return true;
154}
155
156// >STATE:* message support. State messages are of the form:
157// >STATE:<date>,<state>,<detail>,<local-ip>,<remote-ip>
158// where:
159// <date> is the current time (since epoch) in seconds
160// <state> is one of:
161// INITIAL, CONNECTING, WAIT, AUTH, GET_CONFIG, ASSIGN_IP, ADD_ROUTES,
162// CONNECTED, RECONNECTING, EXITING, RESOLVE, TCP_CONNECT
163// <detail> is a free-form string giving details about the state change
164// <local-ip> is a dotted-quad for the local IPv4 address (when available)
165// <remote-ip> is a dotted-quad for the remote IPv4 address (when available)
166bool OpenVPNManagementServer::ProcessStateMessage(const string &message) {
167 if (!StartsWithASCII(message, ">STATE:", true)) {
168 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200169 }
Darin Petkov271fe522012-03-27 13:47:29 +0200170 vector<string> details;
171 SplitString(message, ',', &details);
172 if (details.size() > 1) {
173 if (details[1] == "RECONNECTING") {
174 driver_->OnReconnecting();
175 }
176 // The rest of the states are currently ignored.
Darin Petkov78f63262012-03-26 01:30:24 +0200177 }
Darin Petkov271fe522012-03-27 13:47:29 +0200178 return true;
Darin Petkov78f63262012-03-26 01:30:24 +0200179}
180
181void OpenVPNManagementServer::Send(const string &data) {
182 VLOG(2) << __func__ << "(" << data << ")";
183 ssize_t len = sockets_->Send(connected_socket_, data.data(), data.size(), 0);
184 PLOG_IF(ERROR, len < 0 || static_cast<size_t>(len) != data.size())
185 << "Send failed: " << data;
186}
187
188void OpenVPNManagementServer::SendState(const string &state) {
189 VLOG(2) << __func__ << "(" << state << ")";
190 Send(StringPrintf("state %s\n", state.c_str()));
Darin Petkov1c115202012-03-22 15:35:47 +0100191}
192
193} // namespace shill