PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/ax25-tools/ax25/rxecho.c

#
C | 517 lines | 330 code | 83 blank | 104 comment | 108 complexity | ac23ed4ec3c5d2b61b570dd12974cacd MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * rxecho.c - Copies AX.25 packets from an interface to another interface.
  3. * Reads CONFIGFILE (see below) and uses that information to
  4. * decide what packets should be copied and where.
  5. *
  6. * CONFIGFILE format is:
  7. *
  8. * # this is a comment
  9. * 144 kiss0 oh2bns-1,oh2bns-2
  10. * kiss0 144 *
  11. *
  12. * This means that packets received on port 144 are copied to port
  13. * kiss0 if they are destined to oh2bns-1 or oh2bns-2. Packets
  14. * from port kiss0 are all copied to port 144.
  15. *
  16. * There may be empty lines and an arbirary amount of white
  17. * space around the tokens but the callsign field must not
  18. * have any spaces in it. There can be up to MAXCALLS call-
  19. * signs in the callsign field (see below).
  20. *
  21. * Copyright (C) 1996 by Tomi Manninen, OH2BNS, <oh2bns@sral.fi>.
  22. *
  23. * *** Modified 9/9/96 by Heikki Hannikainen, OH7LZB, <oh7lzb@sral.fi>:
  24. *
  25. * One port can actually be echoed to multiple ports (with a
  26. * different recipient callsign, of course). The old behaviour was
  27. * to give up on the first matching port, even if the recipient
  28. * callsign didn't match (and the frame wasn't echoed anywhere).
  29. *
  30. * *** 20021206 dl9sau:
  31. * - fixed a bug preventing echo to multible ports; it may also
  32. * lead to retransmission on the interface where it came from
  33. * - fixed problem that frames via sendto(...,alen) had a wrong
  34. * protocol (because alen became larger than the size of
  35. * struct sockaddr).
  36. * - sockaddr_pkt is the right struct for recvfrom/sendto on
  37. * type SOCK_PACKET family AF_INET sockets.
  38. * - added support for new PF_PACKET family with sockaddr_ll
  39. *
  40. * ***
  41. *
  42. * This program is free software; you can redistribute it and/or modify
  43. * it under the terms of the GNU General Public License as published by
  44. * the Free Software Foundation; either version 2 of the License, or
  45. * (at your option) any later version.
  46. *
  47. * This program is distributed in the hope that it will be useful,
  48. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  49. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  50. * GNU General Public License for more details.
  51. *
  52. * You should have received a copy of the GNU General Public License
  53. * along with this program; if not, write to the Free Software
  54. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  55. *
  56. */
  57. #include <stdlib.h>
  58. #include <stdio.h>
  59. #include <string.h>
  60. #include <unistd.h>
  61. #include <syslog.h>
  62. #include <signal.h>
  63. #include <sys/types.h>
  64. #include <config.h>
  65. #include <sys/socket.h>
  66. /*
  67. * dl9sau:
  68. * uncomment this if you have problems with sockaddr_pkt.
  69. * sockaddr_pkt is the right way for type SOCK_PACKET on family AF_INET sockets.
  70. * especially because the "sockaddr" on recvfrom is truncated (internaly
  71. * it's sockaddr_pkt) -- and because we use this sockaddr for retransmitting,
  72. * it's really better to use the sockaddr_spkt.
  73. * default is to use SOCKADDR_SPKT
  74. */
  75. #define USE_SOCKADDR_SPKT 1
  76. /* dl9sau: since linux 2.2.x, SOCK_PACKET is obsolete */
  77. #define USE_SOCKADDR_SLL 1
  78. #ifdef USE_SOCKADDR_SLL
  79. #undef USE_SOCKADDR_SPKT
  80. #endif
  81. #include <features.h> /* for the glibc version number */
  82. #if __GLIBC__ >= 2
  83. #ifdef USE_SOCKADDR_SPKT
  84. #include <net/if_packet.h>
  85. #endif
  86. #ifdef USE_SOCKADDR_SLL
  87. #include <sys/ioctl.h>
  88. #include <net/if.h>
  89. #include <netpacket/packet.h>
  90. #endif
  91. #include <net/ethernet.h>
  92. #else
  93. #if defined(USE_SOCKADDR_SPKT) || defined(USE_SOCKADDR_SLL)
  94. #include <asm/types.h>
  95. #include <linux/if_packet.h>
  96. #endif
  97. #include <linux/if_ether.h>
  98. #endif
  99. #include <netinet/in.h>
  100. #ifdef HAVE_NETAX25_AX25_H
  101. #include <netax25/ax25.h>
  102. #else
  103. #include <netax25/kernel_ax25.h>
  104. #endif
  105. #ifdef HAVE_NETROSE_ROSE_H
  106. #include <netrose/rose.h>
  107. #else
  108. #include <netax25/kernel_rose.h>
  109. #endif
  110. #include <netax25/axlib.h>
  111. #include <netax25/axconfig.h>
  112. #include <netax25/daemon.h>
  113. #include "../pathnames.h"
  114. #define MAXCALLS 8
  115. struct config {
  116. char from[14]; /* sockaddr.sa_data is 14 bytes */
  117. int from_idx;
  118. char to[14];
  119. int to_idx;
  120. ax25_address calls[MAXCALLS];/* list of calls to echo */
  121. int ncalls; /* number of calls to echo */
  122. struct config *next;
  123. };
  124. static int logging = FALSE;
  125. static void terminate(int sig)
  126. {
  127. if (logging) {
  128. syslog(LOG_INFO, "terminating on SIGTERM\n");
  129. closelog();
  130. }
  131. exit(0);
  132. }
  133. /*
  134. * Read string "call1,call2,call3,..." into p.
  135. */
  136. static int read_calls(struct config *p, char *s)
  137. {
  138. char *cp, *cp1;
  139. if (p == NULL || s == NULL)
  140. return -1;
  141. p->ncalls = 0;
  142. if (strcmp(s, "*") == 0)
  143. return 0;
  144. cp = s;
  145. while ((cp1 = strchr(cp, ',')) != NULL && p->ncalls < MAXCALLS) {
  146. *cp1 = 0;
  147. if (ax25_aton_entry(cp, p->calls[p->ncalls].ax25_call) == -1)
  148. return -1;
  149. p->ncalls++;
  150. cp = ++cp1;
  151. }
  152. if (p->ncalls < MAXCALLS) {
  153. if (ax25_aton_entry(cp, p->calls[p->ncalls].ax25_call) == -1)
  154. return -1;
  155. p->ncalls++;
  156. }
  157. return p->ncalls;
  158. }
  159. static struct config *readconfig(void)
  160. {
  161. FILE *fp;
  162. char line[80], *cp, *dev;
  163. struct config *p, *list = NULL;
  164. if ((fp = fopen(CONF_RXECHO_FILE, "r")) == NULL) {
  165. fprintf(stderr, "rxecho: cannot open config file\n");
  166. return NULL;
  167. }
  168. while (fgets(line, 80, fp) != NULL) {
  169. cp = strtok(line, " \t\r\n");
  170. if (cp == NULL || cp[0] == '#')
  171. continue;
  172. if ((p = calloc(1, sizeof(struct config))) == NULL) {
  173. perror("rxecho: malloc");
  174. return NULL;
  175. }
  176. if ((dev = ax25_config_get_dev(cp)) == NULL) {
  177. fprintf(stderr, "rxecho: invalid port name - %s\n", cp);
  178. return NULL;
  179. }
  180. strcpy(p->from, dev);
  181. p->from_idx = -1;
  182. if ((cp = strtok(NULL, " \t\r\n")) == NULL) {
  183. fprintf(stderr, "rxecho: config file error.\n");
  184. return NULL;
  185. }
  186. if ((dev = ax25_config_get_dev(cp)) == NULL) {
  187. fprintf(stderr, "rxecho: invalid port name - %s\n", cp);
  188. return NULL;
  189. }
  190. strcpy(p->to, dev);
  191. p->to_idx = -1;
  192. if (read_calls(p, strtok(NULL, " \t\r\n")) == -1) {
  193. fprintf(stderr, "rxecho: config file error.\n");
  194. return NULL;
  195. }
  196. p->next = list;
  197. list = p;
  198. }
  199. fclose(fp);
  200. if (list == NULL)
  201. fprintf(stderr, "rxecho: Empty config file!\n");
  202. return list;
  203. }
  204. /*
  205. * Slightly modified from linux/include/net/ax25.h and
  206. * linux/net/ax25/ax25_subr.c:
  207. */
  208. #if 0
  209. #define C_COMMAND 1
  210. #define C_RESPONSE 2
  211. #define LAPB_C 0x80
  212. #endif
  213. #define LAPB_E 0x01
  214. #define AX25_ADDR_LEN 7
  215. #define AX25_REPEATED 0x80
  216. typedef struct {
  217. ax25_address calls[AX25_MAX_DIGIS];
  218. unsigned char repeated[AX25_MAX_DIGIS];
  219. char ndigi;
  220. char lastrepeat;
  221. } ax25_digi;
  222. /*
  223. * Given an AX.25 address pull of to, from, digi list, and the start of data.
  224. */
  225. static unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi)
  226. {
  227. int d = 0;
  228. if (len < 14) return NULL;
  229. #if 0
  230. if (flags != NULL) {
  231. *flags = 0;
  232. if (buf[6] & LAPB_C) {
  233. *flags = C_COMMAND;
  234. }
  235. if (buf[13] & LAPB_C) {
  236. *flags = C_RESPONSE;
  237. }
  238. }
  239. if (dama != NULL)
  240. *dama = ~buf[13] & DAMA_FLAG;
  241. #endif
  242. /* Copy to, from */
  243. if (dest != NULL)
  244. memcpy(dest, buf + 0, AX25_ADDR_LEN);
  245. if (src != NULL)
  246. memcpy(src, buf + 7, AX25_ADDR_LEN);
  247. buf += 2 * AX25_ADDR_LEN;
  248. len -= 2 * AX25_ADDR_LEN;
  249. digi->lastrepeat = -1;
  250. digi->ndigi = 0;
  251. while (!(buf[-1] & LAPB_E)) {
  252. if (d >= AX25_MAX_DIGIS) return NULL; /* Max of 6 digis */
  253. if (len < 7) return NULL; /* Short packet */
  254. if (digi != NULL) {
  255. memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
  256. digi->ndigi = d + 1;
  257. if (buf[6] & AX25_REPEATED) {
  258. digi->repeated[d] = 1;
  259. digi->lastrepeat = d;
  260. } else {
  261. digi->repeated[d] = 0;
  262. }
  263. }
  264. buf += AX25_ADDR_LEN;
  265. len -= AX25_ADDR_LEN;
  266. d++;
  267. }
  268. return buf;
  269. }
  270. /*
  271. * Check if frame should be echoed. Return 0 if it should and -1 if not.
  272. */
  273. static int check_calls(struct config *cfg, unsigned char *buf, int len)
  274. {
  275. ax25_address dest;
  276. ax25_digi digi;
  277. ax25_address *axp;
  278. int i;
  279. if ((buf[0] & 0x0F) != 0)
  280. return -1; /* don't echo non-data */
  281. if (cfg->ncalls == 0)
  282. return 0; /* copy everything */
  283. if (ax25_parse_addr(++buf, --len, NULL, &dest, &digi) == NULL)
  284. return -1; /* invalid ax.25 header */
  285. /*
  286. * If there are no digis or all digis are already repeated
  287. * use destination address. Else use first non-repeated digi.
  288. */
  289. if (digi.ndigi == 0 || digi.ndigi == digi.lastrepeat + 1)
  290. axp = &dest;
  291. else
  292. axp = &digi.calls[digi.lastrepeat + 1];
  293. for (i = 0; i < cfg->ncalls; i++)
  294. if (ax25_cmp(&cfg->calls[i], axp) == 0)
  295. return 0;
  296. return -1;
  297. }
  298. int main(int argc, char **argv)
  299. {
  300. #ifdef USE_SOCKADDR_SLL
  301. struct sockaddr_ll sll;
  302. struct sockaddr *psa = (struct sockaddr *)&sll;
  303. const int sa_len = sizeof(struct sockaddr_ll);
  304. int from_idx;
  305. #else
  306. #ifdef USE_SOCKADDR_SPKT
  307. struct sockaddr_pkt spkt;
  308. struct sockaddr *psa = (struct sockaddr *)&spkt;
  309. const int sa_len = sizeof(struct sockaddr_pkt);
  310. #else
  311. struct sockaddr sa_generic;
  312. struct sockaddr *psa = (struct sockaddr *)&sa_generic;
  313. const int sa_len = sizeof(struct sockaddr);
  314. #endif
  315. char from_dev_name[sizeof(psa->sa_data)];
  316. #endif
  317. int s, size, alen;
  318. unsigned char buf[1500];
  319. struct config *p, *list;
  320. while ((s = getopt(argc, argv, "lv")) != -1) {
  321. switch (s) {
  322. case 'l':
  323. logging = TRUE;
  324. break;
  325. case 'v':
  326. printf("rxecho: %s\n", VERSION);
  327. return 0;
  328. default:
  329. fprintf(stderr, "usage: rxecho [-l] [-v]\n");
  330. return 1;
  331. }
  332. }
  333. signal(SIGTERM, terminate);
  334. if (ax25_config_load_ports() == 0) {
  335. fprintf(stderr, "rxecho: no AX.25 port data configured\n");
  336. return 1;
  337. }
  338. if ((list = readconfig()) == NULL)
  339. return 1;
  340. #ifdef USE_SOCKADDR_SLL
  341. if ((s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_AX25))) == -1) {
  342. #else
  343. if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) {
  344. #endif
  345. perror("rxecho: socket:");
  346. return 1;
  347. }
  348. #ifdef USE_SOCKADDR_SLL
  349. for (p = list; p != NULL; p = p->next) {
  350. int i;
  351. for (i = 0; i < 2; i++) {
  352. struct config *q;
  353. struct ifreq ifr;
  354. char *p_name = (i ? p->to : p->from);
  355. int *p_idx = (i ? &p->to_idx : &p->from_idx);
  356. /* already set? */
  357. if (*p_idx >= 0)
  358. continue;
  359. strncpy(ifr.ifr_name, p_name, sizeof(ifr.ifr_name)-1);
  360. ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
  361. if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
  362. perror("SIOCGIFINDEX");
  363. return 1;
  364. }
  365. *p_idx = ifr.ifr_ifindex;
  366. for (q = p->next; q != NULL; q = q->next) {
  367. if (q->from_idx < 0 && !strcmp(q->from, p_name))
  368. q->from_idx = *p_idx;
  369. if (q->to_idx < 0 && !strcmp(q->to, p_name))
  370. q->to_idx = *p_idx;
  371. }
  372. }
  373. }
  374. #endif
  375. if (!daemon_start(FALSE)) {
  376. fprintf(stderr, "rxecho: cannot become a daemon\n");
  377. close(s);
  378. return 1;
  379. }
  380. if (logging) {
  381. openlog("rxecho", LOG_PID, LOG_DAEMON);
  382. syslog(LOG_INFO, "starting");
  383. }
  384. for (;;) {
  385. alen = sa_len;
  386. if ((size = recvfrom(s, buf, 1500, 0, psa, &alen)) == -1) {
  387. if (logging) {
  388. syslog(LOG_ERR, "recvfrom: %m");
  389. closelog();
  390. }
  391. return 1;
  392. }
  393. #ifdef USE_SOCKADDR_SLL
  394. from_idx = sll.sll_ifindex;
  395. #else
  396. /*
  397. * dl9sau: save the names of the iface the frame came from;
  398. * we'll overwrite psa->sa_data it for sendto() and need the
  399. * name again when multiplexing to more than one iface
  400. */
  401. strncpy(from_dev_name, psa->sa_data, sizeof(from_dev_name)-1);
  402. from_dev_name[sizeof(from_dev_name)-1] = 0;
  403. #endif
  404. for (p = list; p != NULL; p = p->next)
  405. #ifdef USE_SOCKADDR_SLL
  406. if (p->from_idx == from_idx && (check_calls(p, buf, size) == 0)) {
  407. sll.sll_ifindex = p->to_idx;
  408. #else
  409. if ((strcmp(p->from, from_dev_name) == 0) && (check_calls(p, buf, size) == 0)) {
  410. strcpy(psa->sa_data, p->to);
  411. #endif
  412. /*
  413. * cave: alen (set by recvfrom()) may > salen
  414. * which means it may point beyound of the
  415. * end of the struct. thats why we use the
  416. * correct len (sa_len). this fixes a bug
  417. * where skpt->protocol on sockaddr structs
  418. * pointed behind the struct, leading to
  419. * funny protocol IDs.
  420. * btw, the linux kernel internaly always
  421. * maps to sockaddr to sockaddr_pkt
  422. * on sockets of type SOCK_PACKET on family
  423. * AF_INET. sockaddr_pkt is len 18, sockaddr
  424. * is 16.
  425. */
  426. if (sendto(s, buf, size, 0, psa, sa_len) == -1) {
  427. if (logging) {
  428. syslog(LOG_ERR, "sendto: %m");
  429. closelog();
  430. }
  431. }
  432. }
  433. }
  434. }