1 /* $OpenBSD: npppd_ctl.c,v 1.17 2024/11/21 13:18:38 claudio Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Internet Initiative Japan Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 #include <sys/socket.h> 29 #include <sys/ioctl.h> 30 #include <net/if.h> 31 #include <netinet/in.h> 32 #include <net/pipex.h> 33 34 #include <errno.h> 35 #include <event.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 #include "radish.h" 42 #include "npppd_local.h" 43 #include "npppd.h" 44 #include "log.h" 45 46 struct stopped_ppp { 47 struct npppd_who ppp_who; 48 TAILQ_ENTRY(stopped_ppp) entry; 49 }; 50 51 struct npppd_ctl { 52 u_int *started_ppp; 53 int started_ppp_pos; 54 int started_ppp_siz; 55 TAILQ_HEAD(, stopped_ppp) stopped_ppps; 56 npppd *npppd; 57 bool is_monitoring; 58 bool responding; 59 }; 60 61 static int npppd_ctl_who_walk_rd(struct radish *, void *); 62 static int npppd_ctl_who0 (struct npppd_ctl *, bool); 63 static void npppd_who_init (struct npppd_who *, npppd_ppp *); 64 #ifdef USE_NPPPD_PIPEX 65 static int npppd_ppp_get_pipex_stat(struct npppd_who *_this, npppd_ppp *ppp); 66 #endif 67 68 struct npppd_ctl * 69 npppd_ctl_create(npppd *_this) 70 { 71 struct npppd_ctl *ctl; 72 73 if ((ctl = calloc(1, sizeof(struct npppd_ctl))) == NULL) 74 return (NULL); 75 ctl->npppd = _this; 76 TAILQ_INIT(&ctl->stopped_ppps); 77 78 return (ctl); 79 } 80 81 void 82 npppd_ctl_destroy(struct npppd_ctl *_this) 83 { 84 if (_this != NULL) { 85 free(_this->started_ppp); 86 free(_this); 87 } 88 } 89 90 int 91 npppd_ctl_who(struct npppd_ctl *_this) 92 { 93 return (npppd_ctl_who0(_this, false)); 94 } 95 96 int 97 npppd_ctl_monitor(struct npppd_ctl *_this) 98 { 99 _this->is_monitoring = true; 100 return (0); 101 } 102 103 int 104 npppd_ctl_who_and_monitor(struct npppd_ctl *_this) 105 { 106 return (npppd_ctl_who0(_this, true)); 107 } 108 109 static int 110 npppd_ctl_who0(struct npppd_ctl *_this, bool is_monitoring) 111 { 112 _this->is_monitoring = is_monitoring; 113 _this->responding = true; 114 if (rd_walktree(_this->npppd->rd, npppd_ctl_who_walk_rd, _this) != 0) 115 return (-1); 116 return (0); 117 } 118 119 int 120 npppd_ctl_add_started_ppp_id(struct npppd_ctl *_this, u_int ppp_id) 121 { 122 int started_ppp_siz; 123 u_int *started_ppp; 124 125 if (!_this->is_monitoring && !_this->responding) 126 return (-1); 127 if (_this->started_ppp_pos + 1 >= _this->started_ppp_siz) { 128 started_ppp_siz = _this->started_ppp_siz + 128; 129 started_ppp = reallocarray(_this->started_ppp, 130 started_ppp_siz, sizeof(u_int)); 131 if (started_ppp == NULL) 132 return (-1); 133 _this->started_ppp = started_ppp; 134 _this->started_ppp_siz = started_ppp_siz; 135 } 136 _this->started_ppp[_this->started_ppp_pos++] = ppp_id; 137 138 /* reset the event */ 139 140 return (0); 141 } 142 143 int 144 npppd_ctl_add_stopped_ppp(struct npppd_ctl *_this, npppd_ppp *ppp) 145 { 146 struct stopped_ppp *stopped; 147 148 if (!_this->is_monitoring) 149 return (-1); 150 if ((stopped = malloc(sizeof(struct stopped_ppp))) == NULL) { 151 log_warn("malloc() failed in %s()", __func__); 152 return (-1); 153 } 154 npppd_who_init(&stopped->ppp_who, ppp); 155 TAILQ_INSERT_TAIL(&_this->stopped_ppps, stopped, entry); 156 157 return (0); 158 } 159 160 static int 161 npppd_ctl_who_walk_rd(struct radish *rd, void *ctx) 162 { 163 struct npppd_ctl *_this = ctx; 164 struct sockaddr_npppd *snp; 165 npppd_ppp *ppp; 166 167 snp = rd->rd_rtent; 168 if (snp->snp_type == SNP_PPP) { 169 ppp = snp->snp_data_ptr; 170 if (npppd_ctl_add_started_ppp_id(_this, ppp->id) != 0) 171 return (-1); 172 } 173 174 return (0); 175 } 176 177 int 178 npppd_ctl_disconnect(struct npppd_ctl *_this, u_int *ppp_id, int count) 179 { 180 int i, n; 181 npppd_ppp *ppp; 182 183 for (n = 0, i = 0; i < count; i++) { 184 if ((ppp = npppd_get_ppp_by_id(_this->npppd, ppp_id[i])) 185 != NULL) { 186 ppp_stop(ppp, NULL); 187 n++; 188 } 189 } 190 191 return (n); 192 } 193 194 int 195 npppd_ctl_imsg_compose(struct npppd_ctl *_this, struct imsgbuf *ibuf) 196 { 197 int i, cnt; 198 u_char pktbuf[MAX_IMSGSIZE - IMSG_HEADER_SIZE]; 199 struct npppd_who_list *who_list; 200 npppd_ppp *ppp; 201 struct stopped_ppp *e, *t; 202 203 if (imsgbuf_queuelen(ibuf) > 0) 204 return (0); 205 206 cnt = 0; 207 if (!TAILQ_EMPTY(&_this->stopped_ppps)) { 208 who_list = (struct npppd_who_list *)pktbuf; 209 who_list->more_data = 0; 210 TAILQ_FOREACH_SAFE(e, &_this->stopped_ppps, entry, t) { 211 if (offsetof(struct npppd_who_list, entry[cnt + 1]) 212 > sizeof(pktbuf)) { 213 who_list->more_data = 1; 214 break; 215 } 216 TAILQ_REMOVE(&_this->stopped_ppps, e, entry); 217 memcpy(&who_list->entry[cnt], &e->ppp_who, 218 sizeof(who_list->entry[0])); 219 cnt++; 220 free(e); 221 } 222 who_list->entry_count = cnt; 223 if (imsg_compose(ibuf, IMSG_PPP_STOP, 0, 0, -1, pktbuf, 224 offsetof(struct npppd_who_list, entry[cnt])) == -1) 225 return (-1); 226 227 return (0); 228 } 229 if (_this->responding || _this->started_ppp_pos > 0) { 230 who_list = (struct npppd_who_list *)pktbuf; 231 who_list->more_data = 0; 232 for (cnt = 0, i = 0; i < _this->started_ppp_pos; i++) { 233 if (offsetof(struct npppd_who_list, entry[cnt + 1]) 234 > sizeof(pktbuf)) { 235 who_list->more_data = 1; 236 break; 237 } 238 if ((ppp = npppd_get_ppp_by_id(_this->npppd, 239 _this->started_ppp[i])) == NULL) 240 /* may be disconnected */ 241 continue; 242 npppd_who_init(&who_list->entry[cnt], ppp); 243 cnt++; 244 } 245 who_list->entry_count = cnt; 246 if (imsg_compose(ibuf, IMSG_PPP_START, 0, 0, -1, pktbuf, 247 offsetof(struct npppd_who_list, entry[cnt])) == -1) 248 return (-1); 249 250 if (_this->started_ppp_pos > i) 251 memmove(&_this->started_ppp[0], 252 &_this->started_ppp[i], 253 sizeof(u_int) * 254 (_this->started_ppp_pos - i)); 255 _this->started_ppp_pos -= i; 256 if (who_list->more_data == 0) 257 _this->responding = false; 258 return (0); 259 } 260 261 return (0); 262 } 263 264 static void 265 npppd_who_init(struct npppd_who *_this, npppd_ppp *ppp) 266 { 267 struct timespec curr_time; 268 npppd_auth_base *realm = ppp->realm; 269 npppd_iface *iface = ppp_iface(ppp); 270 271 strlcpy(_this->username, ppp->username, sizeof(_this->username)); 272 _this->time = ppp->start_time; 273 clock_gettime(CLOCK_MONOTONIC, &curr_time); 274 _this->duration_sec = curr_time.tv_sec - ppp->start_monotime; 275 strlcpy(_this->tunnel_proto, npppd_ppp_tunnel_protocol_name( 276 ppp->pppd, ppp), sizeof(_this->tunnel_proto)); 277 278 _this->tunnel_peer.peer_in4.sin_family = AF_UNSPEC; 279 if (((struct sockaddr *)&ppp->phy_info)->sa_len > 0) { 280 memcpy(&_this->tunnel_peer, &ppp->phy_info, 281 MINIMUM(sizeof(_this->tunnel_peer), 282 ((struct sockaddr *)&ppp->phy_info)->sa_len)); 283 } 284 285 strlcpy(_this->ifname, iface->ifname, sizeof(_this->ifname)); 286 if (realm == NULL) 287 _this->rlmname[0] = '\0'; 288 else 289 strlcpy(_this->rlmname, npppd_auth_get_name(realm), 290 sizeof(_this->rlmname)); 291 292 _this->framed_ip_address = ppp->acct_framed_ip_address; 293 _this->ipackets = ppp->ipackets; 294 _this->opackets = ppp->opackets; 295 _this->ierrors = ppp->ierrors; 296 _this->oerrors = ppp->oerrors; 297 _this->ibytes = ppp->ibytes; 298 _this->obytes = ppp->obytes; 299 _this->ppp_id = ppp->id; 300 _this->mru = ppp->peer_mru; 301 302 #ifdef USE_NPPPD_PIPEX 303 if (ppp->pipex_enabled != 0) { 304 if (npppd_ppp_get_pipex_stat(_this, ppp) != 0) { 305 log_warn( 306 "npppd_ppp_get_pipex_stat() failed in %s", 307 __func__); 308 } 309 } 310 #endif 311 } 312 313 #ifdef USE_NPPPD_PIPEX 314 static int 315 npppd_ppp_get_pipex_stat(struct npppd_who *_this, npppd_ppp *ppp) 316 { 317 npppd_iface *iface = ppp_iface(ppp); 318 struct pipex_session_stat_req req; 319 #ifdef USE_NPPPD_PPPOE 320 pppoe_session *pppoe; 321 #endif 322 #ifdef USE_NPPPD_PPTP 323 pptp_call *pptp; 324 #endif 325 #ifdef USE_NPPPD_L2TP 326 l2tp_call *l2tp; 327 #endif 328 329 if (ppp->pipex_enabled == 0) 330 return 0; 331 332 memset(&req, 0, sizeof(req)); 333 switch(ppp->tunnel_type) { 334 #ifdef USE_NPPPD_PPPOE 335 case NPPPD_TUNNEL_PPPOE: 336 pppoe = (pppoe_session *)ppp->phy_context; 337 338 /* PPPOE specific information */ 339 req.psr_protocol = PIPEX_PROTO_PPPOE; 340 req.psr_session_id = pppoe->session_id; 341 break; 342 #endif 343 #ifdef USE_NPPPD_PPTP 344 case NPPPD_TUNNEL_PPTP: 345 pptp = (pptp_call *)ppp->phy_context; 346 347 /* PPTP specific information */ 348 req.psr_session_id = pptp->id; 349 req.psr_protocol = PIPEX_PROTO_PPTP; 350 break; 351 #endif 352 #ifdef USE_NPPPD_L2TP 353 case NPPPD_TUNNEL_L2TP: 354 l2tp = (l2tp_call *)ppp->phy_context; 355 356 /* L2TP specific information */ 357 req.psr_session_id = l2tp->session_id; 358 req.psr_protocol = PIPEX_PROTO_L2TP; 359 break; 360 #endif 361 default: 362 errno = EINVAL; 363 return 1; 364 } 365 366 /* update statistics in kernel */ 367 if (ioctl(iface->devf, PIPEXGSTAT, &req) != 0) 368 return 1; 369 370 _this->ipackets += req.psr_stat.ipackets; 371 _this->opackets += req.psr_stat.opackets; 372 _this->ierrors += req.psr_stat.ierrors; 373 _this->oerrors += req.psr_stat.oerrors; 374 _this->ibytes += req.psr_stat.ibytes; 375 _this->obytes += req.psr_stat.obytes; 376 377 return 0; 378 } 379 #endif 380