multilink.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /*
  2. * multilink.c - support routines for multilink.
  3. *
  4. * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. The name(s) of the authors of this software must not be used to
  14. * endorse or promote products derived from this software without
  15. * prior written permission.
  16. *
  17. * 3. Redistributions of any form whatsoever must retain the following
  18. * acknowledgment:
  19. * "This product includes software developed by Paul Mackerras
  20. * <paulus@samba.org>".
  21. *
  22. * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
  23. * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  24. * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  25. * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  26. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  27. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  28. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  29. */
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <stdlib.h>
  33. #include <netdb.h>
  34. #include <errno.h>
  35. #include <signal.h>
  36. #include <netinet/in.h>
  37. #include <unistd.h>
  38. #include "pppd.h"
  39. #include "fsm.h"
  40. #include "lcp.h"
  41. #include "tdb.h"
  42. bool endpoint_specified; /* user gave explicit endpoint discriminator */
  43. char *bundle_id; /* identifier for our bundle */
  44. char *blinks_id; /* key for the list of links */
  45. bool doing_multilink; /* multilink was enabled and agreed to */
  46. bool multilink_master; /* we own the multilink bundle */
  47. extern TDB_CONTEXT *pppdb;
  48. extern char db_key[];
  49. static void make_bundle_links __P((int append));
  50. static void remove_bundle_link __P((void));
  51. static void iterate_bundle_links __P((void (*func) __P((char *))));
  52. static int get_default_epdisc __P((struct epdisc *));
  53. static int parse_num __P((char *str, const char *key, int *valp));
  54. static int owns_unit __P((TDB_DATA pid, int unit));
  55. #define set_ip_epdisc(ep, addr) do { \
  56. ep->length = 4; \
  57. ep->value[0] = addr >> 24; \
  58. ep->value[1] = addr >> 16; \
  59. ep->value[2] = addr >> 8; \
  60. ep->value[3] = addr; \
  61. } while (0)
  62. #define LOCAL_IP_ADDR(addr) \
  63. (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \
  64. || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \
  65. || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */
  66. #define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH)
  67. void
  68. mp_check_options()
  69. {
  70. lcp_options *wo = &lcp_wantoptions[0];
  71. lcp_options *ao = &lcp_allowoptions[0];
  72. doing_multilink = 0;
  73. if (!multilink)
  74. return;
  75. /* if we're doing multilink, we have to negotiate MRRU */
  76. if (!wo->neg_mrru) {
  77. /* mrru not specified, default to mru */
  78. wo->mrru = wo->mru;
  79. wo->neg_mrru = 1;
  80. }
  81. ao->mrru = ao->mru;
  82. ao->neg_mrru = 1;
  83. if (!wo->neg_endpoint && !noendpoint) {
  84. /* get a default endpoint value */
  85. wo->neg_endpoint = get_default_epdisc(&wo->endpoint);
  86. }
  87. }
  88. /*
  89. * Make a new bundle or join us to an existing bundle
  90. * if we are doing multilink.
  91. */
  92. int
  93. mp_join_bundle()
  94. {
  95. lcp_options *go = &lcp_gotoptions[0];
  96. lcp_options *ho = &lcp_hisoptions[0];
  97. lcp_options *ao = &lcp_allowoptions[0];
  98. int unit, pppd_pid;
  99. int l, mtu;
  100. char *p;
  101. TDB_DATA key, pid, rec;
  102. if (doing_multilink) {
  103. /* have previously joined a bundle */
  104. if (!go->neg_mrru || !ho->neg_mrru) {
  105. notice("oops, didn't get multilink on renegotiation");
  106. lcp_close(0, "multilink required");
  107. return 0;
  108. }
  109. /* XXX should check the peer_authname and ho->endpoint
  110. are the same as previously */
  111. return 0;
  112. }
  113. if (!go->neg_mrru || !ho->neg_mrru) {
  114. /* not doing multilink */
  115. if (go->neg_mrru)
  116. notice("oops, multilink negotiated only for receive");
  117. mtu = ho->neg_mru? ho->mru: PPP_MRU;
  118. if (mtu > ao->mru)
  119. mtu = ao->mru;
  120. if (demand) {
  121. /* already have a bundle */
  122. cfg_bundle(0, 0, 0, 0);
  123. netif_set_mtu(0, mtu);
  124. return 0;
  125. }
  126. make_new_bundle(0, 0, 0, 0);
  127. set_ifunit(1);
  128. netif_set_mtu(0, mtu);
  129. return 0;
  130. }
  131. doing_multilink = 1;
  132. /*
  133. * Find the appropriate bundle or join a new one.
  134. * First we make up a name for the bundle.
  135. * The length estimate is worst-case assuming every
  136. * character has to be quoted.
  137. */
  138. l = 4 * strlen(peer_authname) + 10;
  139. if (ho->neg_endpoint)
  140. l += 3 * ho->endpoint.length + 8;
  141. if (bundle_name)
  142. l += 3 * strlen(bundle_name) + 2;
  143. bundle_id = malloc(l);
  144. if (bundle_id == 0)
  145. novm("bundle identifier");
  146. p = bundle_id;
  147. p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
  148. if (ho->neg_endpoint || bundle_name)
  149. *p++ = '/';
  150. if (ho->neg_endpoint)
  151. p += slprintf(p, bundle_id+l-p, "%s",
  152. epdisc_to_str(&ho->endpoint));
  153. if (bundle_name)
  154. p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);
  155. /* Make the key for the list of links belonging to the bundle */
  156. l = p - bundle_id;
  157. blinks_id = malloc(l + 7);
  158. if (blinks_id == NULL)
  159. novm("bundle links key");
  160. slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7);
  161. /*
  162. * For demand mode, we only need to configure the bundle
  163. * and attach the link.
  164. */
  165. mtu = MIN(ho->mrru, ao->mru);
  166. if (demand) {
  167. cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
  168. netif_set_mtu(0, mtu);
  169. script_setenv("BUNDLE", bundle_id + 7, 1);
  170. return 0;
  171. }
  172. /*
  173. * Check if the bundle ID is already in the database.
  174. */
  175. unit = -1;
  176. lock_db();
  177. key.dptr = bundle_id;
  178. key.dsize = p - bundle_id;
  179. pid = tdb_fetch(pppdb, key);
  180. if (pid.dptr != NULL) {
  181. /* bundle ID exists, see if the pppd record exists */
  182. rec = tdb_fetch(pppdb, pid);
  183. if (rec.dptr != NULL && rec.dsize > 0) {
  184. /* make sure the string is null-terminated */
  185. rec.dptr[rec.dsize-1] = 0;
  186. /* parse the interface number */
  187. parse_num(rec.dptr, "IFNAME=ppp", &unit);
  188. /* check the pid value */
  189. if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
  190. || !process_exists(pppd_pid)
  191. || !owns_unit(pid, unit))
  192. unit = -1;
  193. free(rec.dptr);
  194. }
  195. free(pid.dptr);
  196. }
  197. if (unit >= 0) {
  198. /* attach to existing unit */
  199. if (bundle_attach(unit)) {
  200. set_ifunit(0);
  201. script_setenv("BUNDLE", bundle_id + 7, 0);
  202. make_bundle_links(1);
  203. unlock_db();
  204. info("Link attached to %s", ifname);
  205. return 1;
  206. }
  207. /* attach failed because bundle doesn't exist */
  208. }
  209. /* we have to make a new bundle */
  210. make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
  211. set_ifunit(1);
  212. netif_set_mtu(0, mtu);
  213. script_setenv("BUNDLE", bundle_id + 7, 1);
  214. make_bundle_links(0);
  215. unlock_db();
  216. info("New bundle %s created", ifname);
  217. multilink_master = 1;
  218. return 0;
  219. }
  220. void mp_exit_bundle()
  221. {
  222. lock_db();
  223. remove_bundle_link();
  224. unlock_db();
  225. }
  226. static void sendhup(char *str)
  227. {
  228. int pid;
  229. if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) {
  230. if (debug)
  231. dbglog("sending SIGHUP to process %d", pid);
  232. kill(pid, SIGHUP);
  233. }
  234. }
  235. void mp_bundle_terminated()
  236. {
  237. TDB_DATA key;
  238. bundle_terminating = 1;
  239. upper_layers_down(0);
  240. notice("Connection terminated.");
  241. print_link_stats();
  242. if (!demand) {
  243. remove_pidfiles();
  244. script_unsetenv("IFNAME");
  245. }
  246. lock_db();
  247. destroy_bundle();
  248. iterate_bundle_links(sendhup);
  249. key.dptr = blinks_id;
  250. key.dsize = strlen(blinks_id);
  251. tdb_delete(pppdb, key);
  252. unlock_db();
  253. new_phase(PHASE_DEAD);
  254. doing_multilink = 0;
  255. multilink_master = 0;
  256. }
  257. static void make_bundle_links(int append)
  258. {
  259. TDB_DATA key, rec;
  260. char *p;
  261. char entry[32];
  262. int l;
  263. key.dptr = blinks_id;
  264. key.dsize = strlen(blinks_id);
  265. slprintf(entry, sizeof(entry), "%s;", db_key);
  266. p = entry;
  267. if (append) {
  268. rec = tdb_fetch(pppdb, key);
  269. if (rec.dptr != NULL && rec.dsize > 0) {
  270. rec.dptr[rec.dsize-1] = 0;
  271. if (strstr(rec.dptr, db_key) != NULL) {
  272. /* already in there? strange */
  273. warn("link entry already exists in tdb");
  274. return;
  275. }
  276. l = rec.dsize + strlen(entry);
  277. p = malloc(l);
  278. if (p == NULL)
  279. novm("bundle link list");
  280. slprintf(p, l, "%s%s", rec.dptr, entry);
  281. } else {
  282. warn("bundle link list not found");
  283. }
  284. if (rec.dptr != NULL)
  285. free(rec.dptr);
  286. }
  287. rec.dptr = p;
  288. rec.dsize = strlen(p) + 1;
  289. if (tdb_store(pppdb, key, rec, TDB_REPLACE))
  290. error("couldn't %s bundle link list",
  291. append? "update": "create");
  292. if (p != entry)
  293. free(p);
  294. }
  295. static void remove_bundle_link()
  296. {
  297. TDB_DATA key, rec;
  298. char entry[32];
  299. char *p, *q;
  300. int l;
  301. key.dptr = blinks_id;
  302. key.dsize = strlen(blinks_id);
  303. slprintf(entry, sizeof(entry), "%s;", db_key);
  304. rec = tdb_fetch(pppdb, key);
  305. if (rec.dptr == NULL || rec.dsize <= 0) {
  306. if (rec.dptr != NULL)
  307. free(rec.dptr);
  308. return;
  309. }
  310. rec.dptr[rec.dsize-1] = 0;
  311. p = strstr(rec.dptr, entry);
  312. if (p != NULL) {
  313. q = p + strlen(entry);
  314. l = strlen(q) + 1;
  315. memmove(p, q, l);
  316. rec.dsize = p - rec.dptr + l;
  317. if (tdb_store(pppdb, key, rec, TDB_REPLACE))
  318. error("couldn't update bundle link list (removal)");
  319. }
  320. free(rec.dptr);
  321. }
  322. static void iterate_bundle_links(void (*func)(char *))
  323. {
  324. TDB_DATA key, rec, pp;
  325. char *p, *q;
  326. key.dptr = blinks_id;
  327. key.dsize = strlen(blinks_id);
  328. rec = tdb_fetch(pppdb, key);
  329. if (rec.dptr == NULL || rec.dsize <= 0) {
  330. error("bundle link list not found (iterating list)");
  331. if (rec.dptr != NULL)
  332. free(rec.dptr);
  333. return;
  334. }
  335. p = rec.dptr;
  336. p[rec.dsize-1] = 0;
  337. while ((q = strchr(p, ';')) != NULL) {
  338. *q = 0;
  339. key.dptr = p;
  340. key.dsize = q - p;
  341. pp = tdb_fetch(pppdb, key);
  342. if (pp.dptr != NULL && pp.dsize > 0) {
  343. pp.dptr[pp.dsize-1] = 0;
  344. func(pp.dptr);
  345. }
  346. if (pp.dptr != NULL)
  347. free(pp.dptr);
  348. p = q + 1;
  349. }
  350. free(rec.dptr);
  351. }
  352. static int
  353. parse_num(str, key, valp)
  354. char *str;
  355. const char *key;
  356. int *valp;
  357. {
  358. char *p, *endp;
  359. int i;
  360. p = strstr(str, key);
  361. if (p != 0) {
  362. p += strlen(key);
  363. i = strtol(p, &endp, 10);
  364. if (endp != p && (*endp == 0 || *endp == ';')) {
  365. *valp = i;
  366. return 1;
  367. }
  368. }
  369. return 0;
  370. }
  371. /*
  372. * Check whether the pppd identified by `key' still owns ppp unit `unit'.
  373. */
  374. static int
  375. owns_unit(key, unit)
  376. TDB_DATA key;
  377. int unit;
  378. {
  379. char ifkey[32];
  380. TDB_DATA kd, vd;
  381. int ret = 0;
  382. slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit);
  383. kd.dptr = ifkey;
  384. kd.dsize = strlen(ifkey);
  385. vd = tdb_fetch(pppdb, kd);
  386. if (vd.dptr != NULL) {
  387. ret = vd.dsize == key.dsize
  388. && memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
  389. free(vd.dptr);
  390. }
  391. return ret;
  392. }
  393. static int
  394. get_default_epdisc(ep)
  395. struct epdisc *ep;
  396. {
  397. char *p;
  398. struct hostent *hp;
  399. u_int32_t addr;
  400. /* First try for an ethernet MAC address */
  401. p = get_first_ethernet();
  402. if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) {
  403. ep->class = EPD_MAC;
  404. ep->length = 6;
  405. return 1;
  406. }
  407. /* see if our hostname corresponds to a reasonable IP address */
  408. hp = gethostbyname(hostname);
  409. if (hp != NULL) {
  410. addr = *(u_int32_t *)hp->h_addr;
  411. if (!bad_ip_adrs(addr)) {
  412. addr = ntohl(addr);
  413. if (!LOCAL_IP_ADDR(addr)) {
  414. ep->class = EPD_IP;
  415. set_ip_epdisc(ep, addr);
  416. return 1;
  417. }
  418. }
  419. }
  420. return 0;
  421. }
  422. /*
  423. * epdisc_to_str - make a printable string from an endpoint discriminator.
  424. */
  425. static char *endp_class_names[] = {
  426. "null", "local", "IP", "MAC", "magic", "phone"
  427. };
  428. char *
  429. epdisc_to_str(ep)
  430. struct epdisc *ep;
  431. {
  432. static char str[MAX_ENDP_LEN*3+8];
  433. u_char *p = ep->value;
  434. int i, mask = 0;
  435. char *q, c, c2;
  436. if (ep->class == EPD_NULL && ep->length == 0)
  437. return "null";
  438. if (ep->class == EPD_IP && ep->length == 4) {
  439. u_int32_t addr;
  440. GETLONG(addr, p);
  441. slprintf(str, sizeof(str), "IP:%I", htonl(addr));
  442. return str;
  443. }
  444. c = ':';
  445. c2 = '.';
  446. if (ep->class == EPD_MAC && ep->length == 6)
  447. c2 = ':';
  448. else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0)
  449. mask = 3;
  450. q = str;
  451. if (ep->class <= EPD_PHONENUM)
  452. q += slprintf(q, sizeof(str)-1, "%s",
  453. endp_class_names[ep->class]);
  454. else
  455. q += slprintf(q, sizeof(str)-1, "%d", ep->class);
  456. c = ':';
  457. for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) {
  458. if ((i & mask) == 0) {
  459. *q++ = c;
  460. c = c2;
  461. }
  462. q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]);
  463. }
  464. return str;
  465. }
  466. static int hexc_val(int c)
  467. {
  468. if (c >= 'a')
  469. return c - 'a' + 10;
  470. if (c >= 'A')
  471. return c - 'A' + 10;
  472. return c - '0';
  473. }
  474. int
  475. str_to_epdisc(ep, str)
  476. struct epdisc *ep;
  477. char *str;
  478. {
  479. int i, l;
  480. char *p, *endp;
  481. for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) {
  482. int sl = strlen(endp_class_names[i]);
  483. if (strncasecmp(str, endp_class_names[i], sl) == 0) {
  484. str += sl;
  485. break;
  486. }
  487. }
  488. if (i > EPD_PHONENUM) {
  489. /* not a class name, try a decimal class number */
  490. i = strtol(str, &endp, 10);
  491. if (endp == str)
  492. return 0; /* can't parse class number */
  493. str = endp;
  494. }
  495. ep->class = i;
  496. if (*str == 0) {
  497. ep->length = 0;
  498. return 1;
  499. }
  500. if (*str != ':' && *str != '.')
  501. return 0;
  502. ++str;
  503. if (i == EPD_IP) {
  504. u_int32_t addr;
  505. i = parse_dotted_ip(str, &addr);
  506. if (i == 0 || str[i] != 0)
  507. return 0;
  508. set_ip_epdisc(ep, addr);
  509. return 1;
  510. }
  511. if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) {
  512. ep->length = 6;
  513. return 1;
  514. }
  515. p = str;
  516. for (l = 0; l < MAX_ENDP_LEN; ++l) {
  517. if (*str == 0)
  518. break;
  519. if (p <= str)
  520. for (p = str; isxdigit(*p); ++p)
  521. ;
  522. i = p - str;
  523. if (i == 0)
  524. return 0;
  525. ep->value[l] = hexc_val(*str++);
  526. if ((i & 1) == 0)
  527. ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++);
  528. if (*str == ':' || *str == '.')
  529. ++str;
  530. }
  531. if (*str != 0 || (ep->class == EPD_MAC && l != 6))
  532. return 0;
  533. ep->length = l;
  534. return 1;
  535. }