Annotation of embedaddon/libpdel/ppp/ppp_l2tp_server.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include "ppp/ppp_defs.h"
! 42: #include "ppp/ppp_log.h"
! 43: #include "ppp/ppp_engine.h"
! 44: #include "ppp/ppp_fsm_option.h"
! 45: #include "ppp/ppp_auth.h"
! 46: #include "ppp/ppp_lcp.h"
! 47: #include "ppp/ppp_link.h"
! 48: #include "ppp/ppp_channel.h"
! 49: #include "ppp/ppp_l2tp_avp.h"
! 50: #include "ppp/ppp_l2tp_server.h"
! 51: #include "ppp/ppp_l2tp_ctrl.h"
! 52:
! 53: #include <net/ethernet.h>
! 54: #include <netinet/in_systm.h>
! 55: #include <netinet/ip.h>
! 56: #include <netinet/udp.h>
! 57:
! 58: #include <netgraph/ng_ksocket.h>
! 59:
! 60: #define L2TP_MTYPE "ppp_l2tp"
! 61: #define L2TP_OUTPUT_MTYPE "ppp_l2tp.output"
! 62: #define L2TP_DEVICE_MTYPE "ppp_l2tp.device"
! 63: #define L2TP_PEER_MTYPE "ppp_l2tp.peer"
! 64:
! 65: /* Win2k is too stupid to handle changing the UDP port */
! 66: #define L2TP_CHANGE_PORT 0
! 67:
! 68: #if 0 /* win2k seems to require at least 1500 */
! 69: #define L2TP_MRU \
! 70: (ETHER_MAX_LEN /* standard ethernet frame */ \
! 71: - ETHER_CRC_LEN /* ethernet crc */ \
! 72: - ETHER_HDR_LEN /* ethernet header */ \
! 73: - sizeof(struct ip) /* ip header */ \
! 74: - sizeof(struct udp) /* udp header */ \
! 75: - 10 /* l2tp header */
! 76: - 2) /* ppp protocol field */
! 77: #else
! 78: #define L2TP_MRU LCP_DEFAULT_MRU
! 79: #endif
! 80:
! 81: #define L2TP_MRRU LCP_DEFAULT_MRRU
! 82:
! 83: /* L2TP server info */
! 84: struct ppp_l2tp_server {
! 85: struct ppp_l2tp_server_info info; /* client info */
! 86: struct ppp_log *log; /* ppp log */
! 87: struct ppp_engine *engine; /* ppp engine */
! 88: struct ghash *peers; /* active peers */
! 89: struct pevent_ctx *ev_ctx; /* event context */
! 90: pthread_mutex_t *mutex; /* mutex */
! 91: struct in_addr ip; /* server ip address */
! 92: u_int16_t port; /* server udp port */
! 93: int sock; /* udp listen socket */
! 94: struct pevent *sock_event; /* event context */
! 95: };
! 96:
! 97: /* We keep one of these for each control connection */
! 98: struct ppp_l2tp_peer {
! 99: struct ppp_l2tp_server *s; /* pointer to server */
! 100: struct ppp_l2tp_ctrl *ctrl; /* ctrl connection */
! 101: void *carg; /* client callbck arg */
! 102: struct ppp_l2tp_sess *sess; /* l2tp session */
! 103: struct ppp_channel *chan; /* pointer to channel */
! 104: struct ppp_auth_config auth; /* auth config */
! 105: char node[32]; /* node path */
! 106: char hook[NG_HOOKSIZ]; /* node hook */
! 107: char logname[32]; /* peer logname */
! 108: struct in_addr ip; /* peer ip address */
! 109: u_int16_t port; /* peer port */
! 110: u_char closed; /* closed by client */
! 111: };
! 112:
! 113: /* L2TP control callbacks */
! 114: static ppp_l2tp_ctrl_terminated_t ppp_l2tp_server_ctrl_terminated;
! 115: static ppp_l2tp_initiated_t ppp_l2tp_server_initiated;
! 116: static ppp_l2tp_connected_t ppp_l2tp_server_connected;
! 117: static ppp_l2tp_terminated_t ppp_l2tp_server_terminated;
! 118:
! 119: static const struct ppp_l2tp_ctrl_cb ppp_l2tp_server_ctrl_cb = {
! 120: ppp_l2tp_server_ctrl_terminated,
! 121: ppp_l2tp_server_initiated,
! 122: ppp_l2tp_server_connected,
! 123: ppp_l2tp_server_terminated,
! 124: NULL,
! 125: NULL,
! 126: };
! 127:
! 128: /* Device methods */
! 129: static ppp_channel_open_t ppp_l2tp_server_device_open;
! 130: static ppp_channel_close_t ppp_l2tp_server_device_close;
! 131: static ppp_channel_destroy_t ppp_l2tp_server_device_destroy;
! 132: static ppp_channel_free_output_t ppp_l2tp_server_device_free_output;
! 133: static ppp_channel_set_link_info_t ppp_l2tp_server_device_set_link_info;
! 134: static ppp_channel_get_origination_t ppp_l2tp_server_device_get_origination;
! 135: static ppp_channel_get_node_t ppp_l2tp_server_device_get_node;
! 136: static ppp_channel_get_hook_t ppp_l2tp_server_device_get_hook;
! 137: static ppp_channel_is_async_t ppp_l2tp_server_device_is_async;
! 138: static ppp_channel_get_mtu_t ppp_l2tp_server_device_get_mtu;
! 139: static ppp_channel_get_acfcomp_t ppp_l2tp_server_device_get_acfcomp;
! 140: static ppp_channel_get_pfcomp_t ppp_l2tp_server_device_get_pfcomp;
! 141:
! 142: static struct ppp_channel_meth ppp_l2tp_server_device_meth = {
! 143: ppp_l2tp_server_device_open,
! 144: ppp_l2tp_server_device_close,
! 145: ppp_l2tp_server_device_destroy,
! 146: ppp_l2tp_server_device_free_output,
! 147: ppp_l2tp_server_device_set_link_info,
! 148: ppp_l2tp_server_device_get_origination,
! 149: ppp_l2tp_server_device_get_node,
! 150: ppp_l2tp_server_device_get_hook,
! 151: ppp_l2tp_server_device_is_async,
! 152: ppp_l2tp_server_device_get_mtu,
! 153: ppp_l2tp_server_device_get_acfcomp,
! 154: ppp_l2tp_server_device_get_pfcomp,
! 155: };
! 156:
! 157: /* Other internal functions */
! 158: static int ppp_l2tp_server_new_sess(struct ppp_l2tp_peer *peer,
! 159: struct ppp_l2tp_sess *sess);
! 160: static void ppp_l2tp_server_destroy(struct ppp_l2tp_server **sp);
! 161: static void ppp_l2tp_server_peer_destroy(struct ppp_l2tp_peer **peerp);
! 162: static void ppp_l2tp_server_device_output(struct ppp_l2tp_peer *peer,
! 163: enum ppp_channeloutput type, ...);
! 164: static void ppp_l2tp_server_close_client(struct ppp_l2tp_peer *peer);
! 165:
! 166: static pevent_handler_t ppp_l2tp_server_sock_event;
! 167:
! 168: static const int one = 1;
! 169:
! 170: /* Macro for logging */
! 171: #define LOG(sev, fmt, args...) PPP_LOG(s->log, sev, fmt , ## args)
! 172:
! 173: /***********************************************************************
! 174: PUBLIC FUNCTIONS
! 175: ***********************************************************************/
! 176:
! 177: /*
! 178: * Start the L2TP server associated with a ppp engine.
! 179: */
! 180: int
! 181: ppp_l2tp_server_start(struct ppp_engine *engine,
! 182: const struct ppp_l2tp_server_info *info,
! 183: struct in_addr ip, u_int16_t port, u_int max_conn)
! 184: {
! 185: struct ppp_log *const elog = ppp_engine_get_log(engine);
! 186: struct sockaddr_in sin;
! 187: struct ppp_l2tp_server *s;
! 188:
! 189: /* Sanity */
! 190: if (engine == NULL || info->arg == NULL) {
! 191: errno = EINVAL;
! 192: return (-1);
! 193: }
! 194:
! 195: /* See if server already exists */
! 196: if ((s = ppp_engine_get_l2tp_server(engine)) != NULL) {
! 197: errno = EALREADY;
! 198: return (-1);
! 199: }
! 200:
! 201: /* Create new server */
! 202: if ((s = MALLOC(L2TP_MTYPE, sizeof(*s))) == NULL)
! 203: return (-1);
! 204: memset(s, 0, sizeof(*s));
! 205: s->engine = engine;
! 206: s->ev_ctx = ppp_engine_get_ev_ctx(engine);
! 207: s->mutex = ppp_engine_get_mutex(engine);
! 208: s->sock = -1;
! 209: s->log = ppp_log_dup(elog);
! 210: s->info = *info;
! 211: s->ip = ip;
! 212: s->port = (port != 0) ? port : L2TP_PORT;
! 213:
! 214: /* Create control connection hash table */
! 215: if ((s->peers = ghash_create(s, 0, 0,
! 216: L2TP_MTYPE, NULL, NULL, NULL, NULL)) == NULL) {
! 217: ppp_log_put(elog, LOG_ERR, "ghash_create: %m");
! 218: goto fail;
! 219: }
! 220:
! 221: /* Setup UDP socket that listens for new connections */
! 222: if ((s->sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
! 223: ppp_log_put(elog, LOG_ERR, "socket: %m");
! 224: goto fail;
! 225: }
! 226: if (setsockopt(s->sock, SOL_SOCKET,
! 227: SO_REUSEADDR, &one, sizeof(one)) == -1) {
! 228: ppp_log_put(elog, LOG_ERR, "setsockopt: %m");
! 229: goto fail;
! 230: }
! 231: if (setsockopt(s->sock, SOL_SOCKET,
! 232: SO_REUSEPORT, &one, sizeof(one)) == -1) {
! 233: ppp_log_put(elog, LOG_ERR, "setsockopt: %m");
! 234: goto fail;
! 235: }
! 236: memset(&sin, 0, sizeof(sin));
! 237: #ifndef __linux__
! 238: sin.sin_len = sizeof(sin);
! 239: #endif
! 240: sin.sin_family = AF_INET;
! 241: sin.sin_addr = ip;
! 242: sin.sin_port = htons(s->port);
! 243: if (bind(s->sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
! 244: ppp_log_put(elog, LOG_ERR, "bind: %m");
! 245: goto fail;
! 246: }
! 247: if (pevent_register(s->ev_ctx, &s->sock_event, PEVENT_RECURRING,
! 248: s->mutex, ppp_l2tp_server_sock_event, s, PEVENT_READ,
! 249: s->sock) == -1) {
! 250: ppp_log_put(elog, LOG_ERR, "pevent_register: %m");
! 251: goto fail;
! 252: }
! 253:
! 254: /* Done */
! 255: ppp_engine_set_l2tp_server(engine, s);
! 256: return (0);
! 257:
! 258: fail:
! 259: /* Clean up after failure */
! 260: pevent_unregister(&s->sock_event);
! 261: if (s->sock != -1)
! 262: close(s->sock);
! 263: ghash_destroy(&s->peers);
! 264: FREE(L2TP_MTYPE, s);
! 265: return (-1);
! 266: }
! 267:
! 268: /*
! 269: * Stop the L2TP server associated with a ppp engine.
! 270: *
! 271: * We can't completely destroy it, because there may be L2TP devices
! 272: * in use by ppp_link's that still exist. The ppp_link's are responsible
! 273: * for destroying their devices, not us.
! 274: */
! 275: void
! 276: ppp_l2tp_server_stop(struct ppp_engine *engine)
! 277: {
! 278: struct ppp_l2tp_server *s;
! 279:
! 280: /* Get and clear L2TP server */
! 281: if ((s = ppp_engine_get_l2tp_server(engine)) == NULL)
! 282: return;
! 283: ppp_engine_set_l2tp_server(s->engine, NULL);
! 284:
! 285: /* Stop accepting new connections */
! 286: pevent_unregister(&s->sock_event);
! 287: (void)close(s->sock);
! 288: s->sock = -1;
! 289:
! 290: /* If there are no control connections, clean up now */
! 291: if (ghash_size(s->peers) == 0) {
! 292: ppp_l2tp_server_destroy(&s);
! 293: return;
! 294: }
! 295:
! 296: /* Destroy all control connections */
! 297: while (1) {
! 298: struct ppp_l2tp_peer *peer;
! 299: struct ghash_walk walk;
! 300:
! 301: ghash_walk_init(s->peers, &walk);
! 302: while ((peer = ghash_walk_next(s->peers, &walk)) != NULL) {
! 303:
! 304: /*
! 305: * Destroy control connection and session (if any).
! 306: * We do a 'close' before the 'destroy' to cause at
! 307: * least one StopCCN packet to be generated, in an
! 308: * attempt to be a little nicer to the peer.
! 309: */
! 310: if (peer->ctrl != NULL) {
! 311: ppp_l2tp_ctrl_shutdown(peer->ctrl,
! 312: L2TP_RESULT_SHUTDOWN, 0, NULL);
! 313: ppp_l2tp_ctrl_destroy(&peer->ctrl);
! 314: peer->sess = NULL;
! 315: }
! 316:
! 317: /* Notify client side peer is gone */
! 318: ppp_l2tp_server_close_client(peer);
! 319:
! 320: /* Destroy peer if it has no more references */
! 321: if (peer->chan == NULL) {
! 322: ppp_l2tp_server_peer_destroy(&peer);
! 323: break; /* restart; walk is invalid */
! 324: }
! 325: }
! 326: if (peer == NULL)
! 327: break;
! 328: }
! 329: }
! 330:
! 331: /*
! 332: * Destroy the L2TP server object.
! 333: */
! 334: static void
! 335: ppp_l2tp_server_destroy(struct ppp_l2tp_server **sp)
! 336: {
! 337: struct ppp_l2tp_server *const s = *sp;
! 338:
! 339: /* Sanity */
! 340: if (s == NULL)
! 341: return;
! 342: *sp = NULL;
! 343:
! 344: /* Deallocate */
! 345: assert(ghash_size(s->peers) == 0);
! 346: pevent_unregister(&s->sock_event);
! 347: (void)close(s->sock);
! 348: ghash_destroy(&s->peers);
! 349: ppp_log_close(&s->log);
! 350: FREE(L2TP_MTYPE, s);
! 351: }
! 352:
! 353: /*
! 354: * Close a L2TP connection.
! 355: */
! 356: void
! 357: ppp_l2tp_server_close(struct ppp_engine *engine, struct ppp_l2tp_peer **peerp)
! 358: {
! 359: struct ppp_l2tp_peer *const peer = *peerp;
! 360:
! 361: if (peer == NULL)
! 362: return;
! 363: *peerp = NULL;
! 364: peer->carg = NULL; /* don't call client 'destroy' method */
! 365: if (peer->chan != NULL)
! 366: ppp_l2tp_server_device_close(peer->chan);
! 367: }
! 368:
! 369: /*
! 370: * Get the client handle for the L2TP channel associated with a device.
! 371: */
! 372: void *
! 373: ppp_l2tp_server_get_client_info(struct ppp_channel *chan)
! 374: {
! 375: struct ppp_l2tp_peer *const peer = chan->priv;
! 376:
! 377: if (chan->meth != &ppp_l2tp_server_device_meth) {
! 378: errno = EINVAL;
! 379: return (NULL);
! 380: }
! 381: if (peer->carg == NULL)
! 382: errno = ENXIO;
! 383: return (peer->carg);
! 384: }
! 385:
! 386: /***********************************************************************
! 387: L2TP CONTROL CALLBACKS
! 388: ***********************************************************************/
! 389:
! 390: /*
! 391: * This is called when a control connection is terminated for any reason
! 392: * other than a call ppp_l2tp_ctrl_destroy().
! 393: */
! 394: static void
! 395: ppp_l2tp_server_ctrl_terminated(struct ppp_l2tp_ctrl *ctrl,
! 396: u_int16_t result, u_int16_t error, const char *errmsg)
! 397: {
! 398: struct ppp_l2tp_peer *peer = ppp_l2tp_ctrl_get_cookie(ctrl);
! 399: struct ppp_l2tp_server *const s = peer->s;
! 400:
! 401: /* Debugging */
! 402: LOG(LOG_DEBUG, "%s: invoked ctrl=%p errmsg=\"%s\"",
! 403: __FUNCTION__, ctrl, errmsg);
! 404:
! 405: /* Notify client side peer is gone */
! 406: ppp_l2tp_server_close_client(peer);
! 407:
! 408: /* There should be no session */
! 409: assert(peer->sess == NULL);
! 410: peer->ctrl = NULL;
! 411:
! 412: /* Destroy peer if it has no more references */
! 413: if (peer->chan == NULL)
! 414: ppp_l2tp_server_peer_destroy(&peer);
! 415: }
! 416:
! 417: /*
! 418: * This callback is used to report the peer's initiating a new incoming
! 419: * or outgoing call.
! 420: */
! 421: static void
! 422: ppp_l2tp_server_initiated(struct ppp_l2tp_ctrl *ctrl,
! 423: struct ppp_l2tp_sess *sess, int out,
! 424: const struct ppp_l2tp_avp_list *avps)
! 425: {
! 426: struct ppp_l2tp_peer *const peer = ppp_l2tp_ctrl_get_cookie(ctrl);
! 427: struct ppp_l2tp_server *const s = peer->s;
! 428:
! 429: /* Debugging */
! 430: LOG(LOG_DEBUG, "%s: invoked ctrl=%p sess=%p out=%d",
! 431: __FUNCTION__, ctrl, sess, out);
! 432:
! 433: /* If call is incoming, wait for peer to reply */
! 434: if (!out) {
! 435: ppp_l2tp_sess_set_cookie(sess, peer);
! 436: return;
! 437: }
! 438:
! 439: /* Accept call */
! 440: if (ppp_l2tp_server_new_sess(peer, sess) == -1) {
! 441: ppp_l2tp_terminate(sess, L2TP_RESULT_ERROR,
! 442: L2TP_ERROR_GENERIC, strerror(errno));
! 443: return;
! 444: }
! 445:
! 446: /* Notify control code */
! 447: ppp_l2tp_connected(sess, NULL);
! 448: }
! 449:
! 450: /*
! 451: * This callback is used to report successful connection of a remotely
! 452: * initiated incoming call (see ppp_l2tp_initiated_t) or a locally initiated
! 453: * outgoing call (see ppp_l2tp_initiate()).
! 454: */
! 455: static void
! 456: ppp_l2tp_server_connected(struct ppp_l2tp_sess *sess,
! 457: const struct ppp_l2tp_avp_list *avps)
! 458: {
! 459: struct ppp_l2tp_peer *const peer = ppp_l2tp_sess_get_cookie(sess);
! 460: struct ppp_l2tp_server *const s = peer->s;
! 461:
! 462: /* Debugging */
! 463: LOG(LOG_DEBUG, "%s: invoked sess=%p", __FUNCTION__, sess);
! 464:
! 465: /* Accept call */
! 466: if (ppp_l2tp_server_new_sess(peer, sess) == -1) {
! 467: ppp_l2tp_terminate(sess, L2TP_RESULT_ERROR,
! 468: L2TP_ERROR_GENERIC, strerror(errno));
! 469: return;
! 470: }
! 471: }
! 472:
! 473: /*
! 474: * This callback is called when any call, whether successfully connected
! 475: * or not, is terminated for any reason other than explict termination
! 476: * from the link side (via a call to either ppp_l2tp_terminate() or
! 477: * ppp_l2tp_ctrl_destroy()).
! 478: */
! 479: static void
! 480: ppp_l2tp_server_terminated(struct ppp_l2tp_sess *sess,
! 481: u_int16_t result, u_int16_t error, const char *errmsg)
! 482: {
! 483: struct ppp_l2tp_peer *const peer = ppp_l2tp_sess_get_cookie(sess);
! 484: struct ppp_l2tp_server *const s = peer->s;
! 485: char buf[128];
! 486:
! 487: /* Debugging */
! 488: LOG(LOG_DEBUG, "%s: invoked sess=%p", __FUNCTION__, sess);
! 489:
! 490: /* Sanity */
! 491: assert(peer->sess == NULL || peer->sess == sess);
! 492: assert(peer->ctrl != NULL);
! 493:
! 494: /* Control side is notifying us session is down */
! 495: peer->sess = NULL;
! 496: snprintf(buf, sizeof(buf), "result=%u error=%u errmsg=\"%s\"",
! 497: result, error, (errmsg != NULL) ? errmsg : "");
! 498: LOG(LOG_INFO, "call from %s terminated: %s", peer->logname, buf);
! 499:
! 500: /* Notify client side peer is gone */
! 501: ppp_l2tp_server_close_client(peer);
! 502:
! 503: /* Notify PPP stack session is down */
! 504: if (peer->chan != NULL) {
! 505: ppp_l2tp_server_device_output(peer,
! 506: PPP_CHANNEL_OUTPUT_DOWN_FATAL,
! 507: (errmsg != NULL) ? errmsg : "administratively closed");
! 508: }
! 509: }
! 510:
! 511: /***********************************************************************
! 512: INTERNAL FUNCTIONS
! 513: ***********************************************************************/
! 514:
! 515: /*
! 516: * Read an incoming packet that might be a new L2TP connection.
! 517: */
! 518: static void
! 519: ppp_l2tp_server_sock_event(void *arg)
! 520: {
! 521: struct ppp_l2tp_server *const s = arg;
! 522: struct ppp_l2tp_avp_list *avps = NULL;
! 523: struct ppp_l2tp_peer *peer = NULL;
! 524: #if !L2TP_CHANGE_PORT
! 525: union {
! 526: u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
! 527: struct ng_ksocket_sockopt sockopt;
! 528: } sockopt_buf;
! 529: struct ng_ksocket_sockopt *const sockopt = &sockopt_buf.sockopt;
! 530: #endif
! 531: struct ppp_log *log = NULL;
! 532: struct ngm_connect connect;
! 533: struct ngm_rmhook rmhook;
! 534: struct ngm_mkpeer mkpeer;
! 535: struct sockaddr_in peer_sin;
! 536: struct sockaddr_in sin;
! 537: const size_t bufsize = 8192;
! 538: u_int16_t *buf = NULL;
! 539: char hook[NG_HOOKSIZ];
! 540: socklen_t sin_len;
! 541: char namebuf[64];
! 542: ng_ID_t node_id;
! 543: int csock = -1;
! 544: int dsock = -1;
! 545: int len;
! 546:
! 547: /* Allocate buffer */
! 548: if ((buf = MALLOC(TYPED_MEM_TEMP, bufsize)) == NULL) {
! 549: LOG(LOG_ERR, "malloc: %m");
! 550: goto fail;
! 551: }
! 552:
! 553: /* Read packet */
! 554: sin_len = sizeof(peer_sin);
! 555: if ((len = recvfrom(s->sock, buf, bufsize, 0,
! 556: (struct sockaddr *)&peer_sin, &sin_len)) == -1) {
! 557: LOG(LOG_ERR, "recvfrom: %m");
! 558: goto fail;
! 559: }
! 560:
! 561: /* Drop it if it's not an initial L2TP packet */
! 562: if (len < 12)
! 563: goto fail;
! 564: if ((ntohs(buf[0]) & 0xcb0f) != 0xc802 || ntohs(buf[1]) < 12
! 565: || buf[2] != 0 || buf[3] != 0 || buf[4] != 0 || buf[5] != 0)
! 566: goto fail;
! 567:
! 568: /* Create a new peer */
! 569: if ((peer = MALLOC(L2TP_PEER_MTYPE, sizeof(*peer))) == NULL) {
! 570: LOG(LOG_ERR, "malloc: %m");
! 571: return;
! 572: }
! 573: memset(peer, 0, sizeof(*peer));
! 574: peer->s = s;
! 575: peer->ip = peer_sin.sin_addr;
! 576: peer->port = ntohs(peer_sin.sin_port);
! 577:
! 578: /* Check with client library */
! 579: snprintf(peer->logname, sizeof(peer->logname), "%s:%u",
! 580: inet_ntoa(peer_sin.sin_addr), ntohs(peer_sin.sin_port));
! 581: if ((peer->carg = (*s->info.admit)(s->info.arg, peer,
! 582: peer->ip, peer->port, &peer->auth, peer->logname,
! 583: sizeof(peer->logname))) == NULL)
! 584: goto fail;
! 585:
! 586: /* Create vendor name AVP */
! 587: if (s->info.vendor != NULL) {
! 588: if ((avps = ppp_l2tp_avp_list_create()) == NULL) {
! 589: LOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_create");
! 590: goto fail;
! 591: }
! 592: if (ppp_l2tp_avp_list_append(avps, 1, 0, AVP_VENDOR_NAME,
! 593: s->info.vendor, strlen(s->info.vendor)) == -1) {
! 594: LOG(LOG_ERR, "%s: %m", "ppp_l2tp_avp_list_append");
! 595: goto fail;
! 596: }
! 597: }
! 598:
! 599: /* Create a log for the control connection */
! 600: if ((log = ppp_log_prefix(s->log, "%s: ", peer->logname)) == NULL) {
! 601: LOG(LOG_ERR, "%s: %m", "ppp_log_prefix");
! 602: goto fail;
! 603: }
! 604:
! 605: /* Create a new control connection */
! 606: if ((peer->ctrl = ppp_l2tp_ctrl_create(s->ev_ctx, s->mutex,
! 607: &ppp_l2tp_server_ctrl_cb, log, 0, ntohl(peer_sin.sin_addr.s_addr),
! 608: &node_id, hook, avps, NULL, 0)) == NULL) {
! 609: LOG(LOG_ERR, "%s: %m", "ppp_l2tp_ctrl_create");
! 610: goto fail;
! 611: }
! 612: ppp_l2tp_ctrl_set_cookie(peer->ctrl, peer);
! 613: log = NULL; /* log is consumed by control connection */
! 614:
! 615: /* Get a temporary netgraph socket node */
! 616: if (NgMkSockNode(NULL, &csock, &dsock) == -1) {
! 617: LOG(LOG_ERR, "%s: %m", "NgMkSockNode");
! 618: goto fail;
! 619: }
! 620:
! 621: /* Connect to l2tp netgraph node "lower" hook */
! 622: snprintf(namebuf, sizeof(namebuf), "[%lx]:", (u_long)node_id);
! 623: memset(&connect, 0, sizeof(connect));
! 624: strlcpy(connect.path, namebuf, sizeof(connect.path));
! 625: strlcpy(connect.ourhook, hook, sizeof(connect.ourhook));
! 626: strlcpy(connect.peerhook, hook, sizeof(connect.peerhook));
! 627: if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE,
! 628: NGM_CONNECT, &connect, sizeof(connect)) == -1) {
! 629: LOG(LOG_ERR, "%s: %m", "connect");
! 630: goto fail;
! 631: }
! 632:
! 633: /* Write the received packet to the node */
! 634: if (NgSendData(dsock, hook, (u_char *)buf, len) == -1) {
! 635: LOG(LOG_ERR, "%s: %m", "NgSendData");
! 636: goto fail;
! 637: }
! 638:
! 639: /* Disconnect from netgraph node "lower" hook */
! 640: memset(&rmhook, 0, sizeof(rmhook));
! 641: strlcpy(rmhook.ourhook, hook, sizeof(rmhook.ourhook));
! 642: if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE,
! 643: NGM_RMHOOK, &rmhook, sizeof(rmhook)) == -1) {
! 644: LOG(LOG_ERR, "%s: %m", "rmhook");
! 645: goto fail;
! 646: }
! 647:
! 648: /* Attach a new UDP socket to "lower" hook */
! 649: memset(&mkpeer, 0, sizeof(mkpeer));
! 650: strlcpy(mkpeer.type, NG_KSOCKET_NODE_TYPE, sizeof(mkpeer.type));
! 651: strlcpy(mkpeer.ourhook, hook, sizeof(mkpeer.ourhook));
! 652: strlcpy(mkpeer.peerhook, "inet/dgram/udp", sizeof(mkpeer.peerhook));
! 653: if (NgSendMsg(csock, namebuf, NGM_GENERIC_COOKIE,
! 654: NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1) {
! 655: LOG(LOG_ERR, "%s: %m", "mkpeer");
! 656: goto fail;
! 657: }
! 658:
! 659: /* Point name at ksocket node */
! 660: strlcat(namebuf, hook, sizeof(namebuf));
! 661:
! 662: #if !L2TP_CHANGE_PORT
! 663: /* Make UDP port reusable */
! 664: memset(&sockopt_buf, 0, sizeof(sockopt_buf));
! 665: sockopt->level = SOL_SOCKET;
! 666: sockopt->name = SO_REUSEADDR;
! 667: memcpy(sockopt->value, &one, sizeof(int));
! 668: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 669: NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
! 670: LOG(LOG_ERR, "%s: %m", "setsockopt");
! 671: goto fail;
! 672: }
! 673: sockopt->name = SO_REUSEPORT;
! 674: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 675: NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) {
! 676: LOG(LOG_ERR, "%s: %m", "setsockopt");
! 677: goto fail;
! 678: }
! 679: #endif
! 680:
! 681: /* Bind socket to a new port */
! 682: memset(&sin, 0, sizeof(sin));
! 683: #ifndef __linux__
! 684: sin.sin_len = sizeof(sin);
! 685: #endif
! 686: sin.sin_family = AF_INET;
! 687: sin.sin_addr = s->ip;
! 688: #if L2TP_CHANGE_PORT
! 689: sin.sin_port = 0; /* "choose any free port" */
! 690: #else
! 691: sin.sin_port = htons(s->port);
! 692: #endif
! 693: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 694: NGM_KSOCKET_BIND, &sin, sizeof(sin)) == -1) {
! 695: LOG(LOG_ERR, "%s: %m", "bind");
! 696: goto fail;
! 697: }
! 698:
! 699: #if L2TP_CHANGE_PORT
! 700: /* Set up reverse NAT mapping for the new port */
! 701: if (s->info.natmap != NULL) {
! 702: struct ng_mesg *const reply = (struct ng_mesg *)buf;
! 703: struct sockaddr_in *const self_sin
! 704: = (struct sockaddr_in *)reply->data;
! 705:
! 706: /* Get kernel-assigned UDP port number */
! 707: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 708: NGM_KSOCKET_GETNAME, NULL, 0) == -1) {
! 709: LOG(LOG_ERR, "%s: %m", "getsockname");
! 710: goto fail;
! 711: }
! 712: if (NgRecvMsg(csock, reply, bufsize, NULL) == -1) {
! 713: LOG(LOG_ERR, "%s: %m", "recvmsg");
! 714: goto fail;
! 715: }
! 716: if ((*s->info.natmap)(s->info.arg, self_sin->sin_addr,
! 717: ntohs(self_sin->sin_port), s->port, peer_sin.sin_addr,
! 718: ntohs(peer_sin.sin_port)) == -1) {
! 719: LOG(LOG_ERR, "%s: %m", "can't reverse NAT map");
! 720: goto fail;
! 721: }
! 722: }
! 723: #endif
! 724:
! 725: /* Connect socket to remote peer's IP and port */
! 726: if (NgSendMsg(csock, namebuf, NGM_KSOCKET_COOKIE,
! 727: NGM_KSOCKET_CONNECT, &peer_sin, sizeof(peer_sin)) == -1
! 728: && errno != EINPROGRESS) {
! 729: LOG(LOG_ERR, "%s: %m", "connect");
! 730: goto fail;
! 731: }
! 732:
! 733: /* Add peer to our hash table */
! 734: if (ghash_put(s->peers, peer) == -1) {
! 735: LOG(LOG_ERR, "%s: %m", "ghash_put");
! 736: goto fail;
! 737: }
! 738:
! 739: /* Clean up and return */
! 740: ppp_l2tp_avp_list_destroy(&avps);
! 741: (void)close(csock);
! 742: (void)close(dsock);
! 743: FREE(TYPED_MEM_TEMP, buf);
! 744: return;
! 745:
! 746: fail:
! 747: /* Clean up after failure */
! 748: if (csock != -1)
! 749: (void)close(csock);
! 750: if (dsock != -1)
! 751: (void)close(dsock);
! 752: if (peer != NULL) {
! 753: ppp_l2tp_server_close_client(peer);
! 754: ppp_l2tp_ctrl_destroy(&peer->ctrl);
! 755: FREE(L2TP_PEER_MTYPE, peer);
! 756: }
! 757: ppp_l2tp_avp_list_destroy(&avps);
! 758: ppp_log_close(&log);
! 759: FREE(TYPED_MEM_TEMP, buf);
! 760: }
! 761:
! 762: /*
! 763: * Create a new L2TP peer object corresponding to a L2TP channel
! 764: * and start up a new PPP link/bundle.
! 765: */
! 766: static int
! 767: ppp_l2tp_server_new_sess(struct ppp_l2tp_peer *peer, struct ppp_l2tp_sess *sess)
! 768: {
! 769: struct ppp_l2tp_server *const s = peer->s;
! 770: struct ppp_link_config link_config;
! 771: struct ppp_log *log = NULL;
! 772: const char *hook;
! 773: ng_ID_t node_id;
! 774: int esave;
! 775:
! 776: /* We allow only one session per control connection */
! 777: if (peer->sess != NULL) {
! 778: errno = EALREADY;
! 779: return (-1);
! 780: }
! 781:
! 782: /* Get this link's node and hook */
! 783: ppp_l2tp_sess_get_hook(sess, &node_id, &hook);
! 784: snprintf(peer->node, sizeof(peer->node), "[%lx]:", (u_long)node_id);
! 785: strlcpy(peer->hook, hook, sizeof(peer->hook));
! 786:
! 787: /* Create a new PPP device for this session */
! 788: if ((peer->chan = MALLOC(L2TP_DEVICE_MTYPE,
! 789: sizeof(*peer->chan))) == NULL) {
! 790: LOG(LOG_ERR, "can't allocate new channel: %m");
! 791: goto fail;
! 792: }
! 793: memset(peer->chan, 0, sizeof(*peer->chan));
! 794: peer->chan->meth = &ppp_l2tp_server_device_meth;
! 795: peer->chan->priv = peer;
! 796:
! 797: /* Create device output message port */
! 798: if ((peer->chan->outport
! 799: = mesg_port_create("ppp_l2tp_server")) == NULL) {
! 800: LOG(LOG_ERR, "can't create mesg_port: %m");
! 801: goto fail;
! 802: }
! 803:
! 804: /* Create log for the new PPP link by prefixing the engine's log */
! 805: if ((log = ppp_engine_get_log(s->engine)) != NULL
! 806: && (log = ppp_log_prefix(log, "%s: ", peer->logname)) == NULL) {
! 807: LOG(LOG_ERR, "can't create link log: %m");
! 808: goto fail;
! 809: }
! 810:
! 811: /* Configure the new PPP link */
! 812: memset(&link_config, 0, sizeof(link_config));
! 813: link_config.auth = peer->auth;
! 814: link_config.max_self_mru = L2TP_MRU;
! 815: link_config.max_self_mrru = L2TP_MRRU;
! 816: link_config.multilink = 1;
! 817: link_config.eid.class = PPP_EID_CLASS_IP;
! 818: link_config.eid.length = sizeof(s->ip);
! 819: memcpy(link_config.eid.value, &s->ip, sizeof(s->ip));
! 820:
! 821: /* Add new link to the PPP engine */
! 822: if (ppp_link_create(s->engine, peer->chan, &link_config, log) == -1) {
! 823: LOG(LOG_ERR, "can't create link: %m");
! 824: goto fail;
! 825: }
! 826: log = NULL;
! 827:
! 828: /* Notify PPP engine link is up */
! 829: ppp_l2tp_server_device_output(peer, PPP_CHANNEL_OUTPUT_UP);
! 830:
! 831: /* Done */
! 832: peer->sess = sess;
! 833: return (0);
! 834:
! 835: fail:
! 836: /* Clean up after failure */
! 837: esave = errno;
! 838: ppp_log_close(&log);
! 839: if (peer->chan != NULL) {
! 840: if (peer->chan->outport != NULL)
! 841: mesg_port_destroy(&peer->chan->outport);
! 842: FREE(L2TP_DEVICE_MTYPE, peer->chan);
! 843: }
! 844: errno = esave;
! 845: return (-1);
! 846: }
! 847:
! 848: /*
! 849: * Output indication from the device.
! 850: */
! 851: static void
! 852: ppp_l2tp_server_device_output(struct ppp_l2tp_peer *peer,
! 853: enum ppp_channeloutput type, ...)
! 854: {
! 855: struct ppp_l2tp_server *const s = peer->s;
! 856: struct ppp_channel_output *output;
! 857:
! 858: /* Get output object */
! 859: if ((output = MALLOC(L2TP_OUTPUT_MTYPE, sizeof(*output))) == NULL) {
! 860: LOG(LOG_ERR, "can't create l2tp output: %m");
! 861: return;
! 862: }
! 863: memset(output, 0, sizeof(*output));
! 864: output->type = type;
! 865:
! 866: /* Get extra args */
! 867: switch (output->type) {
! 868: case PPP_CHANNEL_OUTPUT_DOWN_FATAL:
! 869: case PPP_CHANNEL_OUTPUT_DOWN_NONFATAL:
! 870: {
! 871: const char *msg;
! 872: va_list args;
! 873:
! 874: /* Get string message */
! 875: va_start(args, type);
! 876: msg = va_arg(args, const char *);
! 877: va_end(args);
! 878: if ((output->info = STRDUP(L2TP_OUTPUT_MTYPE, msg)) == NULL) {
! 879: LOG(LOG_ERR, "can't create l2tp output: %m");
! 880: FREE(L2TP_OUTPUT_MTYPE, output);
! 881: return;
! 882: }
! 883: break;
! 884: }
! 885: case PPP_CHANNEL_OUTPUT_UP:
! 886: break;
! 887: }
! 888:
! 889: /* Send message */
! 890: if (mesg_port_put(peer->chan->outport, output) == -1) {
! 891: LOG(LOG_ERR, "can't send l2tp output: %m");
! 892: ppp_l2tp_server_device_free_output(peer->chan, output);
! 893: return;
! 894: }
! 895: }
! 896:
! 897: /*
! 898: * Notify client code that connection is gone.
! 899: * Make sure that we only do this once however.
! 900: */
! 901: static void
! 902: ppp_l2tp_server_close_client(struct ppp_l2tp_peer *peer)
! 903: {
! 904: struct ppp_l2tp_server *const s = peer->s;
! 905: void *const peer_carg = peer->carg;
! 906:
! 907: if (peer_carg == NULL)
! 908: return;
! 909: peer->carg = NULL;
! 910: (*s->info.destroy)(s->info.arg, peer_carg);
! 911: }
! 912:
! 913: /*
! 914: * Destroy a peer.
! 915: */
! 916: static void
! 917: ppp_l2tp_server_peer_destroy(struct ppp_l2tp_peer **peerp)
! 918: {
! 919: struct ppp_l2tp_peer *peer = *peerp;
! 920: struct ppp_l2tp_server *s;
! 921:
! 922: /* Sanity checks */
! 923: if (peer == NULL)
! 924: return;
! 925: *peerp = NULL;
! 926: assert(peer->ctrl == NULL);
! 927: assert(peer->sess == NULL);
! 928: assert(peer->chan == NULL);
! 929:
! 930: /* Destroy peer */
! 931: s = peer->s;
! 932: ghash_remove(s->peers, peer);
! 933: FREE(L2TP_PEER_MTYPE, peer);
! 934:
! 935: /* Destroy server if shutting down and no more peers left */
! 936: if (s->sock == -1 && ghash_size(s->peers) == 0)
! 937: ppp_l2tp_server_destroy(&s);
! 938: }
! 939:
! 940: /***********************************************************************
! 941: L2TP DEVICE METHODS
! 942: ***********************************************************************/
! 943:
! 944: static void
! 945: ppp_l2tp_server_device_open(struct ppp_channel *chan)
! 946: {
! 947: return;
! 948: }
! 949:
! 950: static void
! 951: ppp_l2tp_server_device_close(struct ppp_channel *chan)
! 952: {
! 953: struct ppp_l2tp_peer *const peer = chan->priv;
! 954: struct ppp_l2tp_server *const s = peer->s;
! 955:
! 956: /* Logging */
! 957: if (!peer->closed) {
! 958: LOG(LOG_INFO, "closing L2TP connection with %s", peer->logname);
! 959: peer->closed = 1;
! 960: }
! 961:
! 962: /* Terminate the L2TP channel */
! 963: if (peer->sess != NULL) {
! 964: ppp_l2tp_terminate(peer->sess, L2TP_RESULT_ADMIN, 0, NULL);
! 965: peer->sess = NULL;
! 966: }
! 967:
! 968: /* Notify upper layers link is down */
! 969: ppp_l2tp_server_device_output(peer,
! 970: PPP_CHANNEL_OUTPUT_DOWN_FATAL, "administratively closed");
! 971: }
! 972:
! 973: static void
! 974: ppp_l2tp_server_device_destroy(struct ppp_channel **chanp)
! 975: {
! 976: struct ppp_channel *const chan = *chanp;
! 977: struct ppp_channel_output *output;
! 978: struct ppp_l2tp_peer *peer;
! 979: struct ppp_l2tp_server *s;
! 980:
! 981: /* Sanity */
! 982: if (chan == NULL)
! 983: return;
! 984: *chanp = NULL;
! 985: peer = chan->priv;
! 986: assert(peer->chan == chan);
! 987: s = peer->s;
! 988:
! 989: /* Close client code's side of the device */
! 990: ppp_l2tp_server_close_client(peer);
! 991:
! 992: /* Terminate the L2TP channel */
! 993: if (peer->sess != NULL) {
! 994: ppp_l2tp_terminate(peer->sess, L2TP_RESULT_ADMIN, 0, NULL);
! 995: peer->sess = NULL;
! 996: }
! 997:
! 998: /* Destroy the device object */
! 999: while ((output = mesg_port_get(chan->outport, 0)) != NULL)
! 1000: ppp_l2tp_server_device_free_output(chan, output);
! 1001: mesg_port_destroy(&chan->outport);
! 1002: FREE(L2TP_DEVICE_MTYPE, chan);
! 1003: peer->chan = NULL;
! 1004:
! 1005: /* Destroy peer if it has no more references */
! 1006: if (peer->ctrl == NULL)
! 1007: ppp_l2tp_server_peer_destroy(&peer);
! 1008: }
! 1009:
! 1010: static void
! 1011: ppp_l2tp_server_device_free_output(struct ppp_channel *chan,
! 1012: struct ppp_channel_output *output)
! 1013: {
! 1014: FREE(L2TP_OUTPUT_MTYPE, output->info);
! 1015: FREE(L2TP_OUTPUT_MTYPE, output);
! 1016: }
! 1017:
! 1018: static void
! 1019: ppp_l2tp_server_device_set_link_info(struct ppp_channel *chan, u_int32_t accm)
! 1020: {
! 1021: /* XXX implement me? */
! 1022: }
! 1023:
! 1024: static int
! 1025: ppp_l2tp_server_device_get_origination(struct ppp_channel *chan)
! 1026: {
! 1027: return (PPP_PEER); /* we don't initiate any calls ourself */
! 1028: }
! 1029:
! 1030: static const char *
! 1031: ppp_l2tp_server_device_get_node(struct ppp_channel *chan)
! 1032: {
! 1033: struct ppp_l2tp_peer *const peer = chan->priv;
! 1034:
! 1035: return (peer->node);
! 1036: }
! 1037:
! 1038: static const char *
! 1039: ppp_l2tp_server_device_get_hook(struct ppp_channel *chan)
! 1040: {
! 1041: struct ppp_l2tp_peer *const peer = chan->priv;
! 1042:
! 1043: return (peer->hook);
! 1044: }
! 1045:
! 1046: static int
! 1047: ppp_l2tp_server_device_is_async(struct ppp_channel *chan)
! 1048: {
! 1049: return (0);
! 1050: }
! 1051:
! 1052: static u_int
! 1053: ppp_l2tp_server_device_get_mtu(struct ppp_channel *chan)
! 1054: {
! 1055: return (L2TP_MRU);
! 1056: }
! 1057:
! 1058: static int
! 1059: ppp_l2tp_server_device_get_acfcomp(struct ppp_channel *chan)
! 1060: {
! 1061: return (1);
! 1062: }
! 1063:
! 1064: static int
! 1065: ppp_l2tp_server_device_get_pfcomp(struct ppp_channel *chan)
! 1066: {
! 1067: return (1);
! 1068: }
! 1069:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>