blob: d53881a165e892535ed8641fa93a32d4b4de4877 [file] [log] [blame]
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001/* minimalistic telnet/network interface it might turn into a wire interface */
2/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21#include <sys/socket.h>
22#include <netinet/in.h>
Sylvain Munauta9efc122012-03-01 20:41:40 +010023#include <errno.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020024#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010029#include <osmocom/core/msgb.h>
Sylvain Munauta9efc122012-03-01 20:41:40 +010030#include <osmocom/core/socket.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010031#include <osmocom/core/talloc.h>
32#include <osmocom/core/logging.h>
Holger Hans Peter Freyther2c9168c2013-10-10 20:21:33 +020033#include <osmocom/core/signal.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020034
35#include <osmocom/vty/telnet_interface.h>
36#include <osmocom/vty/buffer.h>
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +080037#include <osmocom/vty/command.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020038
Harald Weltee881b1b2011-08-17 18:52:30 +020039/*! \addtogroup telnet_interface
Harald Welte7acb30c2011-08-17 17:13:48 +020040 * @{
Harald Welte96e2a002017-06-12 21:44:18 +020041 * \brief Telnet interface towards Osmocom VTY
42 *
43 * This module contains the code implementing a telnet server for VTY
44 * access. This telnet server gets linked into each libosmovty-using
45 * process in order to enable interactive command-line introspection,
46 * interaction and configuration.
Harald Welte7acb30c2011-08-17 17:13:48 +020047 */
48/*! \file telnet_interface.c */
49
Harald Welte3fb0b6f2010-05-19 19:02:52 +020050/* per connection data */
51LLIST_HEAD(active_connections);
52
53static void *tall_telnet_ctx;
54
55/* per network data */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020056static int telnet_new_connection(struct osmo_fd *fd, unsigned int what);
Harald Welte3fb0b6f2010-05-19 19:02:52 +020057
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020058static struct osmo_fd server_socket = {
Harald Welte3fb0b6f2010-05-19 19:02:52 +020059 .when = BSC_FD_READ,
60 .cb = telnet_new_connection,
61 .priv_nr = 0,
62};
63
Sylvain Munauta9efc122012-03-01 20:41:40 +010064/*! \brief Initialize telnet based VTY interface listening to 127.0.0.1
Harald Welte7acb30c2011-08-17 17:13:48 +020065 * \param[in] tall_ctx \ref talloc context
66 * \param[in] priv private data to be passed to callback
67 * \param[in] port UDP port number
68 */
Harald Welte3fb0b6f2010-05-19 19:02:52 +020069int telnet_init(void *tall_ctx, void *priv, int port)
70{
Sylvain Munauta9efc122012-03-01 20:41:40 +010071 return telnet_init_dynif(tall_ctx, priv, "127.0.0.1", port);
72}
73
74/*! \brief Initialize telnet based VTY interface
75 * \param[in] tall_ctx \ref talloc context
76 * \param[in] priv private data to be passed to callback
77 * \param[in] ip IP to listen to ('::1' for localhost, '::0' for all, ...)
78 * \param[in] port UDP port number
79 */
80int telnet_init_dynif(void *tall_ctx, void *priv, const char *ip, int port)
81{
82 int rc;
Harald Welte3fb0b6f2010-05-19 19:02:52 +020083
84 tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
Sylvain Munauta9efc122012-03-01 20:41:40 +010085 "telnet_connection");
Harald Welte3fb0b6f2010-05-19 19:02:52 +020086
Sylvain Munauta9efc122012-03-01 20:41:40 +010087 rc = osmo_sock_init_ofd(
88 &server_socket,
89 AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP,
90 ip, port, OSMO_SOCK_F_BIND
91 );
Harald Welte3fb0b6f2010-05-19 19:02:52 +020092
93 server_socket.data = priv;
Harald Welte3fb0b6f2010-05-19 19:02:52 +020094
Neels Hofmeyr55dc2ed2016-09-19 14:10:25 +020095 if (rc < 0) {
96 LOGP(DLGLOBAL, LOGL_ERROR, "Cannot bind telnet at %s %d\n",
97 ip, port);
98 return -1;
99 }
100
101 LOGP(DLGLOBAL, LOGL_NOTICE, "telnet at %s %d\n", ip, port);
102 return 0;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200103}
104
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +0800105extern struct host host;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200106
Harald Welte7acb30c2011-08-17 17:13:48 +0200107/*! \brief close a telnet connection */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200108int telnet_close_client(struct osmo_fd *fd)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200109{
110 struct telnet_connection *conn = (struct telnet_connection*)fd->data;
111
112 close(fd->fd);
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200113 osmo_fd_unregister(fd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200114
115 if (conn->dbg) {
116 log_del_target(conn->dbg);
117 talloc_free(conn->dbg);
118 }
119
120 llist_del(&conn->entry);
121 talloc_free(conn);
122 return 0;
123}
124
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200125static int client_data(struct osmo_fd *fd, unsigned int what)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200126{
127 struct telnet_connection *conn = fd->data;
128 int rc = 0;
129
130 if (what & BSC_FD_READ) {
131 conn->fd.when &= ~BSC_FD_READ;
132 rc = vty_read(conn->vty);
133 }
134
135 /* vty might have been closed from vithin vty_read() */
Holger Hans Peter Freythereb55e6a2014-07-01 19:39:26 +0200136 if (rc == -EBADF)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200137 return rc;
138
139 if (what & BSC_FD_WRITE) {
140 rc = buffer_flush_all(conn->vty->obuf, fd->fd);
141 if (rc == BUFFER_EMPTY)
142 conn->fd.when &= ~BSC_FD_WRITE;
143 }
144
145 return rc;
146}
147
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200148static int telnet_new_connection(struct osmo_fd *fd, unsigned int what)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200149{
150 struct telnet_connection *connection;
151 struct sockaddr_in sockaddr;
152 socklen_t len = sizeof(sockaddr);
153 int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
Harald Welte4a1cb092016-11-26 00:11:53 +0100154 int rc;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200155
156 if (new_connection < 0) {
157 LOGP(0, LOGL_ERROR, "telnet accept failed\n");
158 return new_connection;
159 }
160
161 connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
162 connection->priv = fd->data;
163 connection->fd.data = connection;
164 connection->fd.fd = new_connection;
165 connection->fd.when = BSC_FD_READ;
166 connection->fd.cb = client_data;
Harald Welte4a1cb092016-11-26 00:11:53 +0100167 rc = osmo_fd_register(&connection->fd);
168 if (rc < 0) {
169 talloc_free(connection);
170 return rc;
171 }
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200172 llist_add_tail(&connection->entry, &active_connections);
173
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200174 connection->vty = vty_create(new_connection, connection);
175 if (!connection->vty) {
176 LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
177 close(new_connection);
178 talloc_free(connection);
179 return -1;
180 }
181
182 return 0;
183}
184
Harald Welte7acb30c2011-08-17 17:13:48 +0200185/*! \brief callback from core VTY code about VTY related events */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200186void vty_event(enum event event, int sock, struct vty *vty)
187{
Holger Hans Peter Freyther2c9168c2013-10-10 20:21:33 +0200188 struct vty_signal_data sig_data = { 0, };
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200189 struct telnet_connection *connection = vty->priv;
Holger Hans Peter Freyther2c9168c2013-10-10 20:21:33 +0200190 struct osmo_fd *bfd;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200191
192 if (vty->type != VTY_TERM)
193 return;
194
Holger Hans Peter Freyther2c9168c2013-10-10 20:21:33 +0200195 sig_data.event = event;
196 sig_data.sock = sock;
197 sig_data.vty = vty;
198 osmo_signal_dispatch(SS_L_VTY, S_VTY_EVENT, &sig_data);
199
200 if (!connection)
201 return;
202
203 bfd = &connection->fd;
204
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200205 switch (event) {
206 case VTY_READ:
207 bfd->when |= BSC_FD_READ;
208 break;
209 case VTY_WRITE:
210 bfd->when |= BSC_FD_WRITE;
211 break;
212 case VTY_CLOSED:
213 /* vty layer is about to free() vty */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200214 telnet_close_client(bfd);
215 break;
216 default:
217 break;
218 }
219}
220
Andreas.Eversbergdc3be0a2011-11-06 20:09:28 +0100221void telnet_exit(void)
222{
223 struct telnet_connection *tc, *tc2;
224
225 llist_for_each_entry_safe(tc, tc2, &active_connections, entry)
226 telnet_close_client(&tc->fd);
227
228 osmo_fd_unregister(&server_socket);
229 close(server_socket.fd);
230 talloc_free(tall_telnet_ctx);
231}
232
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200233/*! @} */