mactelnet-0.4.0/0000775000000000000000000000000012001362343012161 5ustar rootrootmactelnet-0.4.0/macping.c0000664000000000000000000002070112001345061013741 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "protocol.h" #include "interfaces.h" #include "config.h" #define MAX_DEVICES 128 #define MT_INTERFACE_LEN 128 #define PROGRAM_NAME "MAC-Ping" #define _(String) gettext (String) static int sockfd, insockfd; static unsigned short ping_size = 38; struct net_interface interfaces[MAX_INTERFACES]; static struct in_addr sourceip; static struct in_addr destip; static unsigned char dstmac[ETH_ALEN]; static int ping_sent = 0; static int pong_received = 0; static float min_ms = FLT_MAX; static float avg_ms = 0; static float max_ms = 0; /* Protocol data direction, not used here, but obligatory for protocol.c */ unsigned char mt_direction_fromserver = 0; static void print_version() { fprintf(stderr, PROGRAM_NAME " " PROGRAM_VERSION "\n"); } static long long int toddiff(struct timeval *tod1, struct timeval *tod2) { long long t1, t2; t1 = tod1->tv_sec * 1000000 + tod1->tv_usec; t2 = tod2->tv_sec * 1000000 + tod2->tv_usec; return t1 - t2; } static void display_results() { int percent = (int)((100.f/ping_sent) * pong_received); if (percent > 100) { percent = 0; } if (percent < 0) { percent = 0; } if (min_ms == FLT_MAX) { min_ms = 0; } printf("\n"); printf(_("%d packets transmitted, %d packets received, %d%% packet loss\n"), ping_sent, pong_received, 100 - percent); printf(_("round-trip min/avg/max = %.2f/%.2f/%.2f ms\n"), min_ms, avg_ms/pong_received, max_ms); /* For bash scripting */ if (pong_received == 0) { exit(1); } exit(0); } int main(int argc, char **argv) { int optval = 1; int print_help = 0; int send_packets = 5; int fastmode = 0; int c; struct sockaddr_in si_me; struct mt_packet packet; int i; setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); while (1) { c = getopt(argc, argv, "fs:c:hv?"); if (c == -1) { break; } switch (c) { case 'f': fastmode = 1; break; case 's': ping_size = atoi(optarg) - 18; break; case 'v': print_version(); exit(0); break; case 'c': send_packets = atoi(optarg); break; case 'h': case '?': print_help = 1; break; } } /* We don't want people to use this for the wrong reasons */ if (fastmode && (send_packets == 0 || send_packets > 100)) { fprintf(stderr, _("Number of packets to send must be more than 0 and less than 100 in fast mode.\n")); return 1; } if (argc - optind < 1 || print_help) { print_version(); fprintf(stderr, _("Usage: %s [-h] [-f] [-c ] [-s ]\n"), argv[0]); if (print_help) { fprintf(stderr, _("\nParameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device.\n" " -f Fast mode, do not wait before sending next ping request.\n" " -s Specify size of ping packet.\n" " -c Number of packets to send. (0 = unlimited)\n" " -h This help.\n" "\n")); } return 1; } if (ping_size > ETH_FRAME_LEN - 42) { fprintf(stderr, _("Packet size must be between 18 and %d\n"), ETH_FRAME_LEN - 42 + 18); exit(1); } /* Mikrotik RouterOS does not answer unless the packet has the correct recipient mac-address in * the ethernet frame. Unlike real MacTelnet connections where the OS is ok with it being a * broadcast mac address. */ if (geteuid() != 0) { fprintf(stderr, _("You need to have root privileges to use %s.\n"), argv[0]); return 1; } /* Get mac-address from string, or check for hostname via mndp */ if (!query_mndp_or_mac(argv[optind], dstmac, 1)) { /* No valid mac address found, abort */ return 1; } sockfd = net_init_raw_socket(); insockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (insockfd < 0) { perror("insockfd"); return 1; } /* Set initialize address/port */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MACTELNET_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); setsockopt(insockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to specified address/port */ if (bind(insockfd, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d\n"), inet_ntoa(si_me.sin_addr), MT_MNDP_PORT); return 1; } /* Listen address*/ inet_pton(AF_INET, (char *)"0.0.0.0", &sourceip); /* Set up global info about the connection */ inet_pton(AF_INET, (char *)"255.255.255.255", &destip); srand(time(NULL)); /* Enumerate available interfaces */ net_get_interfaces(interfaces, MAX_INTERFACES); if (ping_size < sizeof(struct timeval)) { ping_size = sizeof(struct timeval); } signal(SIGINT, display_results); for (i = 0; i < send_packets || send_packets == 0; ++i) { fd_set read_fds; static struct timeval lasttimestamp; int reads, result; struct timeval timeout; int ii; int sent = 0; int waitforpacket; struct timeval timestamp; unsigned char pingdata[1500]; gettimeofday(×tamp, NULL); memcpy(pingdata, ×tamp, sizeof(timestamp)); for (ii = sizeof(timestamp); ii < ping_size; ++ii) { pingdata[ii] = rand() % 256; } for (ii = 0; ii < MAX_INTERFACES; ++ii) { struct net_interface *interface = &interfaces[ii]; if (!interface->in_use) { break; } if (!interface->has_mac) { continue; } init_pingpacket(&packet, interface->mac_addr, dstmac); add_packetdata(&packet, pingdata, ping_size); result = net_send_udp(sockfd, interface, interface->mac_addr, dstmac, &sourceip, MT_MACTELNET_PORT, &destip, MT_MACTELNET_PORT, packet.data, packet.size); if (result > 0) { sent++; } } if (sent == 0) { fprintf(stderr, _("Error sending packet.\n")); continue; } ping_sent++; FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); timeout.tv_sec = 1; timeout.tv_usec = 0; waitforpacket = 1; while (waitforpacket) { /* Wait for data or timeout */ reads = select(insockfd+1, &read_fds, NULL, NULL, &timeout); if (reads <= 0) { waitforpacket = 0; fprintf(stderr, _("%s ping timeout\n"), ether_ntoa((struct ether_addr *)&dstmac)); break; } unsigned char buff[1500]; struct sockaddr_in saddress; unsigned int slen = sizeof(saddress); struct mt_mactelnet_hdr pkthdr; result = recvfrom(insockfd, buff, 1500, 0, (struct sockaddr *)&saddress, &slen); parse_packet(buff, &pkthdr); /* TODO: Check that we are the receiving host */ if (pkthdr.ptype != MT_PTYPE_PONG) { /* Wait for the correct packet */ continue; } struct timeval pongtimestamp; struct timeval nowtimestamp; waitforpacket = 0; gettimeofday(&nowtimestamp, NULL); memcpy(&pongtimestamp, pkthdr.data - 4, sizeof(pongtimestamp)); if (memcmp(pkthdr.data - 4, pingdata, ping_size) == 0) { float diff = toddiff(&nowtimestamp, &pongtimestamp) / 1000.0f; if (diff < min_ms) { min_ms = diff; } if (diff > max_ms) { max_ms = diff; } avg_ms += diff; printf(_("%s %d byte, ping time %.2f ms%s\n"), ether_ntoa((struct ether_addr *)&(pkthdr.srcaddr)), result, diff, (char *)(memcmp(&pongtimestamp,&lasttimestamp,sizeof(lasttimestamp)) == 0 ? " DUP" : "")); } else { printf(_("%s Reply of %d bytes of unequal data\n"), ether_ntoa((struct ether_addr *)&(pkthdr.srcaddr)), result); } pong_received++; memcpy(&lasttimestamp, &pongtimestamp, sizeof(pongtimestamp)); if (!fastmode) { sleep(1); } } } /* Display statistics and exit */ display_results(); return 0; } mactelnet-0.4.0/console.h0000664000000000000000000000207312001345061013774 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ extern int get_terminal_size(unsigned short *width, unsigned short *height); extern int raw_term(); extern int reset_term(); extern int set_terminal_size(int fd, unsigned short width, unsigned short height); mactelnet-0.4.0/mactelnet.h0000664000000000000000000000160612001345061014307 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define CONNECT_TIMEOUT 2 mactelnet-0.4.0/md5.h0000664000000000000000000000650012001345061013016 0ustar rootroot/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ mactelnet-0.4.0/users.h0000664000000000000000000000225112001345061013471 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _USERS_H #define _USERS_H 1 #define MT_CRED_LEN 100 #define MT_CRED_MAXNUM 128 struct mt_credentials { char username[MT_CRED_LEN]; char password[MT_CRED_LEN]; }; extern struct mt_credentials mt_users[MT_CRED_MAXNUM]; extern void read_userfile(); struct mt_credentials* find_user(char *username); #endif mactelnet-0.4.0/Makefile0000664000000000000000000000351312001345061013621 0ustar rootroot CC?=gcc # Run this with make LIBS=-lrt if you want to compile on kfreebsd all: macping mndp mactelnet mactelnetd clean: distclean distclean: rm -f mactelnet macping mactelnetd mndp rm -f po/*.pot rm -f *.o dist: distclean po install: all install-docs install -d $(DESTDIR)/usr/bin install mndp $(DESTDIR)/usr/bin/ install macping $(DESTDIR)/usr/bin/ install mactelnet $(DESTDIR)/usr/bin/ install -d $(DESTDIR)/usr/sbin install -o root mactelnetd $(DESTDIR)/usr/sbin/ install -d $(DESTDIR)/etc install -m 600 -o root config/mactelnetd.users $(DESTDIR)/etc/ install-docs: install -d $(DESTDIR)/usr/share/man/man1/ install docs/*.1 $(DESTDIR)/usr/share/man/man1/ po: po/mactelnet.pot po/mactelnet.pot: *.c xgettext --package-name=mactelnet --msgid-bugs-address=haakon.nessjoen@gmail.com -d mactelnet -C -c_ -k_ -kgettext_noop *.c -o po/mactelnet.pot users.o: users.c users.h ${CC} -Wall ${CFLAGS} -DUSERSFILE='"/etc/mactelnetd.users"' -c users.c protocol.o: protocol.c protocol.h ${CC} -Wall ${CFLAGS} -c protocol.c interfaces.o: interfaces.c interfaces.h ${CC} -Wall ${CFLAGS} -c interfaces.c md5.o: md5.c md5.h ${CC} -Wall ${CFLAGS} -c md5.c mactelnet: config.h mactelnet.c mactelnet.h protocol.o console.c console.h interfaces.o md5.o mndp.c ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o mactelnet mactelnet.c protocol.o console.c interfaces.o md5.o -DFROM_MACTELNET mndp.c ${LIBS} mactelnetd: config.h mactelnetd.c protocol.o interfaces.o console.c console.h users.o users.h md5.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o mactelnetd mactelnetd.c protocol.o console.c interfaces.o users.o md5.o ${LIBS} mndp: config.h mndp.c protocol.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o mndp mndp.c protocol.o ${LIBS} macping: config.h macping.c interfaces.o protocol.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o macping macping.c interfaces.o protocol.o ${LIBS} mactelnet-0.4.0/users.c0000664000000000000000000000363712001345061013475 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include "users.h" #include "config.h" struct mt_credentials mt_users[MT_CRED_MAXNUM]; void read_userfile() { FILE *file = fopen(USERSFILE, "r"); char line [BUFSIZ]; int i = 0; if (file == NULL) { perror(USERSFILE); exit(1); } while ( fgets(line, sizeof line, file) ) { char *user; char *password; user = strtok(line, ":"); password = strtok(NULL, "\n"); if (user == NULL || password == NULL) { continue; } if (user[0] == '#') continue; memcpy(mt_users[i].username, user, strlen(user) < MT_CRED_LEN - 1? strlen(user) : MT_CRED_LEN); memcpy(mt_users[i++].password, password, strlen(password) < MT_CRED_LEN - 1? strlen(password) : MT_CRED_LEN); if (i == MT_CRED_MAXNUM) break; mt_users[i].username[0] = '\0'; } fclose(file); } struct mt_credentials* find_user(char *username) { int i = 0; while (i < MT_CRED_MAXNUM && mt_users[i].username[0] != 0) { if (strcmp(username, mt_users[i].username) == 0) { return &(mt_users[i]); } i++; } return NULL; } mactelnet-0.4.0/LICENSE0000664000000000000000000004325412001345061013174 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. mactelnet-0.4.0/md5.c0000664000000000000000000003022212001345061013007 0ustar rootroot/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } mactelnet-0.4.0/config/0000775000000000000000000000000012001345061013424 5ustar rootrootmactelnet-0.4.0/config/mactelnetd.init0000664000000000000000000000063512001345061016435 0ustar rootroot# mactelnetd - MAC-Telnet server # # The MAC-Telnet server provides telnet access via MAC addresses. # # Ubuntu upstart config: description "MAC-Telnet server" start on filesystem stop on runlevel [!2345] respawn respawn limit 10 5 umask 022 pre-start script test -O /etc/mactelnetd.users || { stop; exit 0; } test -x /usr/sbin/mactelnetd || { stop; exit 0; } end script exec /usr/sbin/mactelnetd -f mactelnet-0.4.0/config/mactelnetd.users0000664000000000000000000000070612001345061016632 0ustar rootroot# Users file for MAC-Telnetd # #################################################################### # WARNING: This file has passwords written in plain-text. # # Make sure this file is owned and only readable by root. # #################################################################### # # Each line consists of a username and a password seperated by :. # Usernames must be existing users from passwd. # # Format: #username:password mactelnet-0.4.0/protocol.h0000664000000000000000000001113712001345061014174 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _MACTELNET_H #define _MACTELNET_H 1 #define MT_HEADER_LEN 22 #define MT_CPHEADER_LEN 9 #define MT_PACKET_LEN 1500 #define MT_MACTELNET_PORT 20561 #define MT_MNDP_PORT 5678 #define MT_MNDP_MAX_STRING_LENGTH 128 #define MT_MNDP_BROADCAST_INTERVAL 30 #define MT_MNDP_TIMEOUT 5 #define MT_MNDP_LONGTIMEOUT 120 #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IPV4_ALEN #define IPV4_ALEN 4 #endif /* Packet type */ enum mt_ptype { MT_PTYPE_SESSIONSTART, MT_PTYPE_DATA, MT_PTYPE_ACK, MT_PTYPE_PING = 4, MT_PTYPE_PONG, MT_PTYPE_END = 255 }; /* Control packet type */ enum mt_cptype { MT_CPTYPE_BEGINAUTH, MT_CPTYPE_ENCRYPTIONKEY, MT_CPTYPE_PASSWORD, MT_CPTYPE_USERNAME, MT_CPTYPE_TERM_TYPE, MT_CPTYPE_TERM_WIDTH, MT_CPTYPE_TERM_HEIGHT, MT_CPTYPE_PACKET_ERROR, MT_CPTYPE_END_AUTH = 9, /* Internal CPTYPE, not part of protocol */ MT_CPTYPE_PLAINDATA = -1 }; /* MNDP attribute type */ enum mt_mndp_attrtype { MT_MNDPTYPE_ADDRESS = 0x0001, MT_MNDPTYPE_IDENTITY = 0x0005, MT_MNDPTYPE_VERSION = 0x0007, MT_MNDPTYPE_PLATFORM = 0x0008, MT_MNDPTYPE_TIMESTAMP = 0x000a, MT_MNDPTYPE_SOFTID = 0x000b, MT_MNDPTYPE_HARDWARE = 0x000c }; /* MNDP packet header */ struct mt_mndp_hdr { unsigned char version; unsigned char ttl; unsigned short cksum; }; struct mt_mactelnet_hdr { unsigned char ver; enum mt_ptype ptype; unsigned char clienttype[2]; unsigned char srcaddr[6]; unsigned char dstaddr[6]; unsigned short seskey; unsigned int counter; unsigned char *data; }; struct mt_mactelnet_control_hdr { enum mt_cptype cptype; unsigned int length; unsigned char *data; }; /* TODO: Add all the other information obtainable from mndp */ struct mt_mndp_info { struct mt_mndp_hdr header; unsigned char address[ETH_ALEN]; char identity[MT_MNDP_MAX_STRING_LENGTH]; char version[MT_MNDP_MAX_STRING_LENGTH]; char platform[MT_MNDP_MAX_STRING_LENGTH]; char hardware[MT_MNDP_MAX_STRING_LENGTH]; char softid[MT_MNDP_MAX_STRING_LENGTH]; unsigned int uptime; }; struct mt_packet { int size; unsigned char data[MT_PACKET_LEN]; }; /* MacTelnet/Winbox packets */ extern int init_packet(struct mt_packet *packet, enum mt_ptype ptype, unsigned char *srcmac, unsigned char *dstmac, unsigned short sessionkey, unsigned int counter); extern int add_control_packet(struct mt_packet *packet, enum mt_cptype cptype, void *cpdata, int data_len); extern void parse_packet(unsigned char *data, struct mt_mactelnet_hdr *pkthdr); extern int parse_control_packet(unsigned char *data, int data_len, struct mt_mactelnet_control_hdr *cpkthdr); /* MAC-Ping packets */ int init_pingpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac); int init_pongpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac); int add_packetdata(struct mt_packet *packet, unsigned char *data, unsigned short length); /* MNDP packets */ extern int mndp_init_packet(struct mt_packet *packet, unsigned char version, unsigned char ttl); extern int mndp_add_attribute(struct mt_packet *packet, enum mt_mndp_attrtype attrtype, void *attrdata, unsigned short data_len); extern struct mt_mndp_info *parse_mndp(const unsigned char *data, const int packet_len); int query_mndp(const char *identity, unsigned char *mac); int query_mndp_or_mac(char *address, unsigned char *dstmac, int verbose); /* Number of milliseconds between each retransmission */ #define MAX_RETRANSMIT_INTERVALS 9 static const int retransmit_intervals[MAX_RETRANSMIT_INTERVALS] = { 15, 20, 30, 50, 90, 170, 330, 660, 1000 }; /* Control packet magic header */ static const unsigned char mt_mactelnet_cpmagic[4] = { 0x56, 0x34, 0x12, 0xff }; static const unsigned char mt_mactelnet_clienttype[2] = { 0x00, 0x15 }; /* Must be initialized by application */ extern unsigned char mt_direction_fromserver; #endif mactelnet-0.4.0/interfaces.c0000664000000000000000000002306212001345061014451 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __linux__ #include #include #include #include #include #else #include #endif #include "protocol.h" #include "interfaces.h" #define _(String) gettext (String) struct net_interface *net_get_interface_ptr(struct net_interface *interfaces, int max_devices, char *name, int create) { int i; for (i = 0; i < max_devices; ++i) { if (!interfaces[i].in_use) break; if (strncmp(interfaces[i].name, name, 254) == 0) { return interfaces + i; } } if (create && i < max_devices) { interfaces[i].in_use = 1; strncpy(interfaces[i].name, name, 254); interfaces[i].name[254] = '\0'; return interfaces + i; } return NULL; } #ifdef __linux__ static void net_update_mac(struct net_interface *interfaces, int max_devices) { unsigned char emptymac[] = {0, 0, 0, 0, 0, 0}; struct ifreq ifr; int i,tmpsock; tmpsock = socket(PF_INET, SOCK_DGRAM, 0); if (tmpsock < 0) { perror("net_update_mac"); exit(1); } for (i = 0; i < max_devices; ++i) { if (interfaces[i].in_use) { /* Find interface hardware address from device_name */ strncpy(ifr.ifr_name, interfaces[i].name, 16); if (ioctl(tmpsock, SIOCGIFHWADDR, &ifr) == 0) { /* Fetch mac address */ memcpy(interfaces[i].mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); if (memcmp(interfaces[i].mac_addr, &emptymac, ETH_ALEN) != 0) { interfaces[i].has_mac = 1; } } } } close(tmpsock); } static int get_device_index(char *device_name) { struct ifreq ifr; int tmpsock; tmpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Find interface index from device_name */ strncpy(ifr.ifr_name, device_name, 16); if (ioctl(tmpsock, SIOCGIFINDEX, &ifr) != 0) { return -1; } /* Return interface index */ return ifr.ifr_ifindex; } #endif int net_get_interfaces(struct net_interface *interfaces, int max_devices) { static struct ifaddrs *int_addrs; static const struct ifaddrs *int_cursor; const struct sockaddr_in *dl_addr; int found = 0; if (getifaddrs(&int_addrs) < 0) { perror("getifaddrs"); exit(1); } for (int_cursor = int_addrs; int_cursor != NULL; int_cursor = int_cursor->ifa_next) { dl_addr = (const struct sockaddr_in *) int_cursor->ifa_addr; if (int_cursor->ifa_addr == NULL) continue; if (int_cursor->ifa_addr->sa_family == AF_INET) { struct net_interface *interface = net_get_interface_ptr(interfaces, max_devices, int_cursor->ifa_name, 1); if (interface != NULL) { found++; memcpy(interface->ipv4_addr, &dl_addr->sin_addr, IPV4_ALEN); } #ifdef __linux__ interface->ifindex = get_device_index(interface->name); #endif } #ifndef __linux__ { unsigned char emptymac[] = {0, 0, 0, 0, 0, 0}; struct sockaddr_dl *sdl = (struct sockaddr_dl *)int_cursor->ifa_addr; if (sdl->sdl_alen == ETH_ALEN) { struct net_interface *interface = net_get_interface_ptr(interfaces, max_devices, int_cursor->ifa_name, 1); memcpy(interface->mac_addr, LLADDR(sdl), ETH_ALEN); if (interface != NULL && memcmp(interface->mac_addr, &emptymac, ETH_ALEN) != 0) { interface->has_mac = 1; } } } #endif } freeifaddrs(int_addrs); #ifdef __linux__ net_update_mac(interfaces, max_devices); #endif #if 0 { int i = 0; for (i = 0; i < max_devices; ++i) { if (interfaces[i].in_use) { struct in_addr *addr = (struct in_addr *)interfaces[i].ipv4_addr; printf("Interface %s:\n", interfaces[i].name); printf("\tIP: %s\n", inet_ntoa(*addr)); printf("\tMAC: %s\n", ether_ntoa((struct ether_addr *)interfaces[i].mac_addr)); #ifdef __linux__ printf("\tIfIndex: %d\n", interfaces[i].ifindex); #endif printf("\n"); } } } #endif return found; } unsigned short in_cksum(unsigned short *addr, int len) { int nleft = len; int sum = 0; unsigned short *w = addr; unsigned short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(unsigned char *) (&answer) = *(unsigned char *) w; sum += answer; } sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16); answer = ~sum; return (answer); } unsigned short udp_sum_calc(unsigned char *src_addr,unsigned char *dst_addr, unsigned char *data, unsigned short len) { unsigned short prot_udp=17; unsigned short padd=0; unsigned short word16; unsigned int sum = 0; int i; /* Padding ? */ padd = (len % 2); if (padd) { data[len] = 0; } /* header+data */ for (i = 0; i < len + padd; i += 2){ word16 = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF); sum += word16; } /* source ip */ for (i = 0; i < IPV4_ALEN; i += 2){ word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i + 1] & 0xFF); sum += word16; } /* dest ip */ for (i = 0; i < IPV4_ALEN; i += 2){ word16 = ((dst_addr[i] << 8) & 0xFF00) + (dst_addr[i + 1] & 0xFF); sum += word16; } sum += prot_udp + len; while (sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); sum = ~sum; if (sum == 0) sum = 0xFFFF; return (unsigned short) sum; } int net_init_raw_socket(struct net_interface *interface) { int fd; #ifdef __linux__ /* Transmit raw packets with this socket */ fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (fd < 0) { perror("raw_socket"); exit(1); } #else /* Transmit raw packets with bpf */ fd = open("/dev/bpf0", O_RDWR); if (fd <= 0) { perror("open_bpf"); exit(1); } #endif return fd; } int net_send_udp(const int fd, struct net_interface *interface, const unsigned char *sourcemac, const unsigned char *destmac, const struct in_addr *sourceip, const int sourceport, const struct in_addr *destip, const int destport, const unsigned char *data, const int datalen) { #ifdef __linux__ struct sockaddr_ll socket_address; #endif /* * Create a buffer for the full ethernet frame * and align header pointers to the correct positions. */ void* buffer = (void*)malloc(ETH_FRAME_LEN); struct ethhdr *eh = (struct ethhdr *)buffer; struct iphdr *ip = (struct iphdr *)(buffer + 14); struct udphdr *udp = (struct udphdr *)(buffer + 14 + 20); unsigned char *rest = (unsigned char *)(buffer + 20 + 14 + sizeof(struct udphdr)); if (((void *)rest - (void*)buffer) + datalen > ETH_FRAME_LEN) { fprintf(stderr, _("packet size too large\n")); free(buffer); return 0; } static unsigned int id = 1; int send_result = 0; /* Abort if we couldn't allocate enough memory */ if (buffer == NULL) { perror("malloc"); exit(1); } /* Init ethernet header */ memcpy(eh->h_source, sourcemac, ETH_ALEN); memcpy(eh->h_dest, destmac, ETH_ALEN); eh->h_proto = htons(ETH_P_IP); #ifdef __linux__ /* Init SendTo struct */ socket_address.sll_family = AF_PACKET; socket_address.sll_protocol = htons(ETH_P_IP); socket_address.sll_ifindex = interface->ifindex; socket_address.sll_hatype = ARPHRD_ETHER; socket_address.sll_pkttype = PACKET_OTHERHOST; socket_address.sll_halen = ETH_ALEN; memcpy(socket_address.sll_addr, eh->h_source, ETH_ALEN); socket_address.sll_addr[6] = 0x00;/*not used*/ socket_address.sll_addr[7] = 0x00;/*not used*/ #endif /* Init IP Header */ ip->version = 4; ip->ihl = 5; ip->tos = 0x10; ip->tot_len = htons(datalen + 8 + 20); ip->id = htons(id++); ip->frag_off = htons(0x4000); ip->ttl = 64; ip->protocol = 17; /* UDP */ ip->check = 0x0000; ip->saddr = sourceip->s_addr; ip->daddr = destip->s_addr; /* Calculate checksum for IP header */ ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); /* Init UDP Header */ udp->source = htons(sourceport); udp->dest = htons(destport); udp->len = htons(sizeof(struct udphdr) + datalen); udp->check = 0; /* Insert actual data */ memcpy(rest, data, datalen); /* Add UDP checksum */ udp->check = udp_sum_calc((unsigned char *)&(ip->saddr), (unsigned char *)&(ip->daddr), (unsigned char *)udp, sizeof(struct udphdr) + datalen); udp->check = htons(udp->check); #ifdef __linux__ /* Send the packet */ send_result = sendto(fd, buffer, datalen + 8 + 14 + 20, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); if (send_result == -1) perror("sendto"); #else { struct ifreq req_if; /* Pick device to send through */ strcpy(req_if.ifr_name, interface->name); if (ioctl(fd, BIOCSETIF, &req_if) > 0) { perror("ioctl_BIOCSETIF"); exit(1); } } send_result = write(fd, buffer, datalen + 8 + 14 + 20); if (send_result == -1) perror("bpf_write"); #endif free(buffer); /* Return amount of _data_ bytes sent */ if (send_result - 8 - 14 - 20 < 0) { return 0; } return send_result - 8 - 14 - 20; } mactelnet-0.4.0/mactelnet.c0000664000000000000000000004447212001345061014312 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __LINUX__ #include #endif #include "md5.h" #include "protocol.h" #include "console.h" #include "interfaces.h" #include "config.h" #include "mactelnet.h" #include "mndp.h" #define PROGRAM_NAME "MAC-Telnet" #define _(String) gettext (String) static int sockfd = 0; static int insockfd; static unsigned int outcounter = 0; static unsigned int incounter = 0; static int sessionkey = 0; static int running = 1; static unsigned char use_raw_socket = 0; static unsigned char terminal_mode = 0; static unsigned char srcmac[ETH_ALEN]; static unsigned char dstmac[ETH_ALEN]; static struct in_addr sourceip; static struct in_addr destip; static int sourceport; static int connect_timeout = CONNECT_TIMEOUT; static int is_a_tty = 1; static int quiet_mode = 0; static int keepalive_counter = 0; static unsigned char encryptionkey[128]; static char username[255]; static char password[255]; static char nonpriv_username[255]; struct net_interface interfaces[MAX_INTERFACES]; struct net_interface *active_interface; /* Protocol data direction */ unsigned char mt_direction_fromserver = 0; static unsigned int send_socket; static int handle_packet(unsigned char *data, int data_len); static void print_version() { fprintf(stderr, PROGRAM_NAME " " PROGRAM_VERSION "\n"); } void drop_privileges(char *username) { struct passwd *user = (struct passwd *) getpwnam(username); if (user == NULL) { fprintf(stderr, _("Failed dropping privileges. The user %s is not a valid username on local system.\n"), username); exit(1); } if (getuid() == 0) { /* process is running as root, drop privileges */ if (setgid(user->pw_gid) != 0) { fprintf(stderr, _("setgid: Error dropping group privileges\n")); exit(1); } if (setuid(user->pw_uid) != 0) { fprintf(stderr, _("setuid: Error dropping user privileges\n")); exit(1); } /* Verify if the privileges were developed. */ if (setuid(0) != -1) { fprintf(stderr, _("Failed to drop privileges\n")); exit(1); } } } static int send_udp(struct mt_packet *packet, int retransmit) { int sent_bytes; /* Clear keepalive counter */ keepalive_counter = 0; if (!use_raw_socket) { /* Init SendTo struct */ struct sockaddr_in socket_address; socket_address.sin_family = AF_INET; socket_address.sin_port = htons(MT_MACTELNET_PORT); socket_address.sin_addr.s_addr = htonl(INADDR_BROADCAST); sent_bytes = sendto(send_socket, packet->data, packet->size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); } else { sent_bytes = net_send_udp(sockfd, active_interface, srcmac, dstmac, &sourceip, sourceport, &destip, MT_MACTELNET_PORT, packet->data, packet->size); } /* * Retransmit packet if no data is received within * retransmit_intervals milliseconds. */ if (retransmit) { int i; for (i = 0; i < MAX_RETRANSMIT_INTERVALS; ++i) { fd_set read_fds; int reads; struct timeval timeout; int interval = retransmit_intervals[i] * 1000; /* Init select */ FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); timeout.tv_sec = 0; timeout.tv_usec = interval; /* Wait for data or timeout */ reads = select(insockfd + 1, &read_fds, NULL, NULL, &timeout); if (reads && FD_ISSET(insockfd, &read_fds)) { unsigned char buff[1500]; int result; bzero(buff, 1500); result = recvfrom(insockfd, buff, 1500, 0, 0, 0); /* Handle incoming packets, waiting for an ack */ if (result > 0 && handle_packet(buff, result) == MT_PTYPE_ACK) { return sent_bytes; } } /* Retransmit */ send_udp(packet, 0); } if (is_a_tty && terminal_mode) { reset_term(); } fprintf(stderr, _("\nConnection timed out\n")); exit(1); } return sent_bytes; } static void send_auth(char *username, char *password) { struct mt_packet data; unsigned short width = 0; unsigned short height = 0; char *terminal = getenv("TERM"); char md5data[100]; unsigned char md5sum[17]; int plen; md5_state_t state; /* Concat string of 0 + password + encryptionkey */ md5data[0] = 0; strncpy(md5data + 1, password, 82); md5data[83] = '\0'; memcpy(md5data + 1 + strlen(password), encryptionkey, 16); /* Generate md5 sum of md5data with a leading 0 */ md5_init(&state); md5_append(&state, (const md5_byte_t *)md5data, strlen(password) + 17); md5_finish(&state, (md5_byte_t *)md5sum + 1); md5sum[0] = 0; /* Send combined packet to server */ init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, outcounter); plen = add_control_packet(&data, MT_CPTYPE_PASSWORD, md5sum, 17); plen += add_control_packet(&data, MT_CPTYPE_USERNAME, username, strlen(username)); plen += add_control_packet(&data, MT_CPTYPE_TERM_TYPE, terminal, strlen(terminal)); if (is_a_tty && get_terminal_size(&width, &height) != -1) { width = htole16(width); height = htole16(height); plen += add_control_packet(&data, MT_CPTYPE_TERM_WIDTH, &width, 2); plen += add_control_packet(&data, MT_CPTYPE_TERM_HEIGHT, &height, 2); } outcounter += plen; /* TODO: handle result */ send_udp(&data, 1); } static void sig_winch(int sig) { unsigned short width,height; struct mt_packet data; int plen; /* terminal height/width has changed, inform server */ if (get_terminal_size(&width, &height) != -1) { init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, outcounter); width = htole16(width); height = htole16(height); plen = add_control_packet(&data, MT_CPTYPE_TERM_WIDTH, &width, 2); plen += add_control_packet(&data, MT_CPTYPE_TERM_HEIGHT, &height, 2); outcounter += plen; send_udp(&data, 1); } /* reinstate signal handler */ signal(SIGWINCH, sig_winch); } static int handle_packet(unsigned char *data, int data_len) { struct mt_mactelnet_hdr pkthdr; parse_packet(data, &pkthdr); /* We only care about packets with correct sessionkey */ if (pkthdr.seskey != sessionkey) { return -1; } /* Handle data packets */ if (pkthdr.ptype == MT_PTYPE_DATA) { struct mt_packet odata; struct mt_mactelnet_control_hdr cpkt; int success = 0; /* Always transmit ACKNOWLEDGE packets in response to DATA packets */ init_packet(&odata, MT_PTYPE_ACK, srcmac, dstmac, sessionkey, pkthdr.counter + (data_len - MT_HEADER_LEN)); send_udp(&odata, 0); /* Accept first packet, and all packets greater than incounter, and if counter has wrapped around. */ if (incounter == 0 || pkthdr.counter > incounter || (incounter - pkthdr.counter) > 65535) { incounter = pkthdr.counter; } else { /* Ignore double or old packets */ return -1; } /* Parse controlpacket data */ success = parse_control_packet(data + MT_HEADER_LEN, data_len - MT_HEADER_LEN, &cpkt); while (success) { /* If we receive encryptionkey, transmit auth data back */ if (cpkt.cptype == MT_CPTYPE_ENCRYPTIONKEY) { memcpy(encryptionkey, cpkt.data, cpkt.length); send_auth(username, password); } /* If the (remaining) data did not have a control-packet magic byte sequence, the data is raw terminal data to be outputted to the terminal. */ else if (cpkt.cptype == MT_CPTYPE_PLAINDATA) { cpkt.data[cpkt.length] = 0; fputs((const char *)cpkt.data, stdout); } /* END_AUTH means that the user/password negotiation is done, and after this point terminal data may arrive, so we set up the terminal to raw mode. */ else if (cpkt.cptype == MT_CPTYPE_END_AUTH) { /* we have entered "terminal mode" */ terminal_mode = 1; if (is_a_tty) { /* stop input buffering at all levels. Give full control of terminal to RouterOS */ raw_term(); setvbuf(stdin, (char*)NULL, _IONBF, 0); /* Add resize signal handler */ signal(SIGWINCH, sig_winch); } } /* Parse next controlpacket */ success = parse_control_packet(NULL, 0, &cpkt); } } else if (pkthdr.ptype == MT_PTYPE_ACK) { /* Handled elsewhere */ } /* The server wants to terminate the connection, we have to oblige */ else if (pkthdr.ptype == MT_PTYPE_END) { struct mt_packet odata; /* Acknowledge the disconnection by sending a END packet in return */ init_packet(&odata, MT_PTYPE_END, srcmac, dstmac, pkthdr.seskey, 0); send_udp(&odata, 0); if (!quiet_mode) { fprintf(stderr, _("Connection closed.\n")); } /* exit */ running = 0; } else { fprintf(stderr, _("Unhandeled packet type: %d received from server %s\n"), pkthdr.ptype, ether_ntoa((struct ether_addr *)dstmac)); return -1; } return pkthdr.ptype; } static int find_interface() { fd_set read_fds; struct mt_packet data; struct sockaddr_in myip; unsigned char emptymac[ETH_ALEN]; int i, testsocket; struct timeval timeout; int optval = 1; /* TODO: reread interfaces on HUP */ bzero(&interfaces, sizeof(struct net_interface) * MAX_INTERFACES); bzero(emptymac, ETH_ALEN); if (net_get_interfaces(interfaces, MAX_INTERFACES) <= 0) { fprintf(stderr, _("Error: No suitable devices found\n")); exit(1); } for (i = 0; i < MAX_INTERFACES; ++i) { if (!interfaces[i].in_use) { break; } /* Skip loopback interfaces */ if (memcmp("lo", interfaces[i].name, 2) == 0) { continue; } /* Initialize receiving socket on the device chosen */ myip.sin_family = AF_INET; memcpy((void *)&myip.sin_addr, interfaces[i].ipv4_addr, IPV4_ALEN); myip.sin_port = htons(sourceport); /* Initialize socket and bind to udp port */ if ((testsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { continue; } setsockopt(testsocket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); setsockopt(testsocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (bind(testsocket, (struct sockaddr *)&myip, sizeof(struct sockaddr_in)) == -1) { close(testsocket); continue; } /* Ensure that we have mac-address for this interface */ if (!interfaces[i].has_mac) { close(testsocket); continue; } /* Set the global socket handle and source mac address for send_udp() */ send_socket = testsocket; memcpy(srcmac, interfaces[i].mac_addr, ETH_ALEN); active_interface = &interfaces[i]; /* Send a SESSIONSTART message with the current device */ init_packet(&data, MT_PTYPE_SESSIONSTART, srcmac, dstmac, sessionkey, 0); send_udp(&data, 0); timeout.tv_sec = connect_timeout; timeout.tv_usec = 0; FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); select(insockfd + 1, &read_fds, NULL, NULL, &timeout); if (FD_ISSET(insockfd, &read_fds)) { /* We got a response, this is the correct device to use */ return 1; } close(testsocket); } return 0; } /* * TODO: Rewrite main() when all sub-functionality is tested */ int main (int argc, char **argv) { int result; struct mt_packet data; struct sockaddr_in si_me; unsigned char buff[1500]; unsigned char print_help = 0, have_username = 0, have_password = 0; unsigned char drop_priv = 0; int c; int optval = 1; setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); while (1) { c = getopt(argc, argv, "lnqt:u:p:U:vh?"); if (c == -1) { break; } switch (c) { case 'n': use_raw_socket = 1; break; case 'u': /* Save username */ strncpy(username, optarg, sizeof(username) - 1); username[sizeof(username) - 1] = '\0'; have_username = 1; break; case 'p': /* Save password */ strncpy(password, optarg, sizeof(password) - 1); password[sizeof(password) - 1] = '\0'; have_password = 1; break; case 'U': /* Save nonpriv_username */ strncpy(nonpriv_username, optarg, sizeof(nonpriv_username) - 1); nonpriv_username[sizeof(nonpriv_username) - 1] = '\0'; drop_priv = 1; break; case 't': connect_timeout = atoi(optarg); break; case 'v': print_version(); exit(0); break; case 'q': quiet_mode = 1; break; case 'l': return mndp(); break; case 'h': case '?': print_help = 1; break; } } if (argc - optind < 1 || print_help) { print_version(); fprintf(stderr, _("Usage: %s [-h] [-n] [-t ] [-u ] [-p ] [-U ] | -l\n"), argv[0]); if (print_help) { fprintf(stderr, _("\nParameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to\n" " discover it.\n" " identity The identity/name of your destination device. Uses\n" " MNDP protocol to find it.\n" " -l List/Search for routers nearby. (using MNDP)\n" " -n Do not use broadcast packets. Less insecure but requires\n" " root privileges.\n" " -t Amount of seconds to wait for a response on each interface.\n" " -u Specify username on command line.\n" " -p Specify password on command line.\n" " -U Drop privileges to this user. Used in conjunction with -n\n" " for security.\n" " -q Quiet mode.\n" " -h This help.\n" "\n")); } return 1; } is_a_tty = isatty(fileno(stdout)) && isatty(fileno(stdin)); if (!is_a_tty) { quiet_mode = 1; } /* Seed randomizer */ srand(time(NULL)); if (use_raw_socket) { if (geteuid() != 0) { fprintf(stderr, _("You need to have root privileges to use the -n parameter.\n")); return 1; } sockfd = net_init_raw_socket(); if (drop_priv) { drop_privileges(nonpriv_username); } } else if (drop_priv) { fprintf(stderr, _("The -U option must be used in conjunction with the -n parameter.\n")); return 1; } /* Receive regular udp packets with this socket */ insockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (insockfd < 0) { perror("insockfd"); return 1; } if (!use_raw_socket) { if (setsockopt(insockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval))==-1) { perror("SO_BROADCAST"); return 1; } } /* Need to use, to be able to autodetect which interface to use */ setsockopt(insockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Get mac-address from string, or check for hostname via mndp */ if (!query_mndp_or_mac(argv[optind], dstmac, !quiet_mode)) { /* No valid mac address found, abort */ return 1; } if (!have_username) { if (!quiet_mode) { printf(_("Login: ")); } scanf("%254s", username); } if (!have_password) { char *tmp; tmp = getpass(quiet_mode ? "" : _("Password: ")); strncpy(password, tmp, sizeof(password) - 1); password[sizeof(password) - 1] = '\0'; /* security */ memset(tmp, 0, strlen(tmp)); #ifdef __GNUC__ free(tmp); #endif } /* Set random source port */ sourceport = 1024 + (rand() % 1024); /* Set up global info about the connection */ inet_pton(AF_INET, (char *)"255.255.255.255", &destip); memcpy(&sourceip, &(si_me.sin_addr), IPV4_ALEN); /* Sessioon key */ sessionkey = rand() % 65535; /* stop output buffering */ setvbuf(stdout, (char*)NULL, _IONBF, 0); if (!quiet_mode) { printf(_("Connecting to %s..."), ether_ntoa((struct ether_addr *)dstmac)); } /* Initialize receiving socket on the device chosen */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(sourceport); /* Bind to udp port */ if (bind(insockfd, (struct sockaddr *)&si_me, sizeof(si_me)) == -1) { fprintf(stderr, _("Error binding to %s:%d, %s\n"), inet_ntoa(si_me.sin_addr), sourceport, strerror(errno)); return 1; } if (!find_interface() || (result = recvfrom(insockfd, buff, 1400, 0, 0, 0)) < 1) { fprintf(stderr, _("Connection failed.\n")); return 1; } if (!quiet_mode) { printf(_("done\n")); } /* Handle first received packet */ handle_packet(buff, result); init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, 0); outcounter += add_control_packet(&data, MT_CPTYPE_BEGINAUTH, NULL, 0); /* TODO: handle result of send_udp */ result = send_udp(&data, 1); while (running) { fd_set read_fds; int reads; static int terminal_gone = 0; struct timeval timeout; /* Init select */ FD_ZERO(&read_fds); if (!terminal_gone) { FD_SET(0, &read_fds); } FD_SET(insockfd, &read_fds); timeout.tv_sec = 1; timeout.tv_usec = 0; /* Wait for data or timeout */ reads = select(insockfd+1, &read_fds, NULL, NULL, &timeout); if (reads > 0) { /* Handle data from server */ if (FD_ISSET(insockfd, &read_fds)) { bzero(buff, 1500); result = recvfrom(insockfd, buff, 1500, 0, 0, 0); handle_packet(buff, result); } /* Handle data from keyboard/local terminal */ if (FD_ISSET(0, &read_fds) && terminal_mode) { unsigned char keydata[512]; int datalen; datalen = read(STDIN_FILENO, &keydata, 512); if (datalen > 0) { /* Data received, transmit to server */ init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, outcounter); add_control_packet(&data, MT_CPTYPE_PLAINDATA, &keydata, datalen); outcounter += datalen; send_udp(&data, 1); } else { terminal_gone = 1; } } /* Handle select() timeout */ } else { /* handle keepalive counter, transmit keepalive packet every 10 seconds of inactivity */ if (keepalive_counter++ == 10) { struct mt_packet odata; init_packet(&odata, MT_PTYPE_ACK, srcmac, dstmac, sessionkey, outcounter); send_udp(&odata, 0); } } } if (is_a_tty && terminal_mode) { /* Reset terminal back to old settings */ reset_term(); } close(sockfd); close(insockfd); return 0; } mactelnet-0.4.0/protocol.c0000664000000000000000000003273312001345061014174 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _BSD_SOURCE #include #include #include #include #include #include #ifdef __LINUX__ #include #endif #include #include #include #include #include #include "protocol.h" #include "config.h" #define _(String) gettext (String) int init_packet(struct mt_packet *packet, enum mt_ptype ptype, unsigned char *srcmac, unsigned char *dstmac, unsigned short sessionkey, unsigned int counter) { unsigned char *data = packet->data; /* Packet version */ data[0] = 1; /* Packet type */ data[1] = ptype; /* src ethernet address */ memcpy(data + 2, srcmac, ETH_ALEN); /* dst ethernet address */ memcpy(data + 8, dstmac, ETH_ALEN); if (mt_direction_fromserver) { /* Session key */ sessionkey = htons(sessionkey); memcpy(data + 16, &sessionkey, sizeof(sessionkey)); /* Client type: Mac Telnet */ memcpy(data + 14, &mt_mactelnet_clienttype, sizeof(mt_mactelnet_clienttype)); } else { /* Session key */ sessionkey = htons(sessionkey); memcpy(data + 14, &sessionkey, sizeof(sessionkey)); /* Client type: Mac Telnet */ memcpy(data + 16, &mt_mactelnet_clienttype, sizeof(mt_mactelnet_clienttype)); } /* Received/sent data counter */ counter = htonl(counter); memcpy(data + 18, &counter, sizeof(counter)); /* 22 bytes header */ packet->size = 22; return 22; } int add_control_packet(struct mt_packet *packet, enum mt_cptype cptype, void *cpdata, int data_len) { unsigned char *data = packet->data + packet->size; /* Something is really wrong. Packets should never become over 1500 bytes */ if (packet->size + MT_CPHEADER_LEN + data_len > MT_PACKET_LEN) { fprintf(stderr, _("add_control_packet: ERROR, too large packet. Exceeds %d bytes\n"), MT_PACKET_LEN); return -1; //exit(1); } /* PLAINDATA isn't really a controlpacket, but we handle it here, since parseControlPacket also parses raw data as PLAINDATA */ if (cptype == MT_CPTYPE_PLAINDATA) { memcpy(data, cpdata, data_len); packet->size += data_len; return data_len; } /* Control Packet Magic id */ memcpy(data, mt_mactelnet_cpmagic, sizeof(mt_mactelnet_cpmagic)); /* Control packet type */ data[4] = cptype; /* Data length */ #if BYTE_ORDER == LITTLE_ENDIAN { unsigned int templen; templen = htonl(data_len); memcpy(data + 5, &templen, sizeof(templen)); } #else memcpy(data + 5, &data_len, sizeof(data_len)); #endif /* Insert data */ if (data_len > 0) { memcpy(data + MT_CPHEADER_LEN, cpdata, data_len); } packet->size += MT_CPHEADER_LEN + data_len; /* Control packet header length + data length */ return MT_CPHEADER_LEN + data_len; } int init_pingpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac) { init_packet(packet, MT_PTYPE_PING, srcmac, dstmac, 0, 0); /* Zero out sessionkey & counter */ bzero(packet->data + 14, 4); /* Remove data counter field from header */ packet->size -= 4; return packet->size; } int init_pongpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac) { init_packet(packet, MT_PTYPE_PONG, srcmac, dstmac, 0, 0); /* Zero out sessionkey & counter */ bzero(packet->data + 14, 4); /* Remove data counter field from header */ packet->size -= 4; return packet->size; } int add_packetdata(struct mt_packet *packet, unsigned char *data, unsigned short length) { if (packet->size + length > MT_PACKET_LEN) { fprintf(stderr, _("add_control_packet: ERROR, too large packet. Exceeds %d bytes\n"), MT_PACKET_LEN); return -1; } memcpy(packet->data + packet->size, data, length); packet->size += length; return length; } void parse_packet(unsigned char *data, struct mt_mactelnet_hdr *pkthdr) { /* Packet version */ pkthdr->ver = data[0]; /* Packet type */ pkthdr->ptype = data[1]; /* src ethernet addr */ memcpy(pkthdr->srcaddr, data + 2, ETH_ALEN); /* dst ethernet addr */ memcpy(pkthdr->dstaddr, data + 8, ETH_ALEN); if (mt_direction_fromserver) { /* Session key */ memcpy(&(pkthdr->seskey), data + 14, sizeof(pkthdr->seskey)); pkthdr->seskey = ntohs(pkthdr->seskey); /* server type */ memcpy(&(pkthdr->clienttype), data + 16, 2); } else { /* server type */ memcpy(&(pkthdr->clienttype), data + 14, 2); /* Session key */ memcpy(&(pkthdr->seskey), data + 16, sizeof(pkthdr->seskey)); pkthdr->seskey = ntohs(pkthdr->seskey); } /* Received/sent data counter */ memcpy(&(pkthdr->counter), data + 18, sizeof(pkthdr->counter)); pkthdr->counter = ntohl(pkthdr->counter); /* Set pointer to actual data */ pkthdr->data = data + 22; } int parse_control_packet(unsigned char *packetdata, int data_len, struct mt_mactelnet_control_hdr *cpkthdr) { static unsigned char *int_data; static unsigned int int_data_len; static unsigned int int_pos; unsigned char *data; /* Store info so we can call this function once with data, and then several times for each control packets. Letting this function control the data position. */ if (packetdata != NULL) { if (data_len <= 0) { return 0; } int_data = packetdata; int_data_len = data_len; int_pos = 0; } /* No more data to parse? */ if (int_pos >= int_data_len) { return 0; } /* Set current position in data buffer */ data = int_data + int_pos; /* Check for valid minimum packet length & magic header */ if (int_data_len >= 9 && memcmp(data, &mt_mactelnet_cpmagic, 4) == 0) { /* Control packet type */ cpkthdr->cptype = data[4]; /* Control packet data length */ memcpy(&(cpkthdr->length), data + 5, sizeof(cpkthdr->length)); cpkthdr->length = ntohl(cpkthdr->length); /* We want no buffer overflows */ if (cpkthdr->length >= MT_PACKET_LEN - 22 - int_pos) { cpkthdr->length = MT_PACKET_LEN - 1 - 22 - int_pos; } /* Set pointer to actual data */ cpkthdr->data = data + 9; /* Remember old position, for next call */ int_pos += cpkthdr->length + 9; /* Read data successfully */ return 1; } else { /* Mark data as raw terminal data */ cpkthdr->cptype = MT_CPTYPE_PLAINDATA; cpkthdr->length = int_data_len - int_pos; cpkthdr->data = data; /* Consume the whole rest of the packet */ int_pos = int_data_len; /* Read data successfully */ return 1; } } int mndp_init_packet(struct mt_packet *packet, unsigned char version, unsigned char ttl) { struct mt_mndp_hdr *header = (struct mt_mndp_hdr *)packet->data; header->version = version; header->ttl = ttl; header->cksum = 0; packet->size = sizeof(header); return sizeof(header); } int mndp_add_attribute(struct mt_packet *packet, enum mt_mndp_attrtype attrtype, void *attrdata, unsigned short data_len) { unsigned char *data = packet->data + packet->size; unsigned short type = attrtype; unsigned short len = data_len; /* Something is really wrong. Packets should never become over 1500 bytes */ if (packet->size + 4 + data_len > MT_PACKET_LEN) { fprintf(stderr, _("mndp_add_attribute: ERROR, too large packet. Exceeds %d bytes\n"), MT_PACKET_LEN); return -1; } type = htons(type); memcpy(data, &type, sizeof(type)); len = htons(len); memcpy(data + 2, &len, sizeof(len)); memcpy(data + 4, attrdata, data_len); packet->size += 4 + data_len; return 4 + data_len; } struct mt_mndp_info *parse_mndp(const unsigned char *data, const int packet_len) { const unsigned char *p; static struct mt_mndp_info packet; struct mt_mndp_hdr *mndp_hdr; /* Check for valid packet length */ if (packet_len < 18) { return NULL; } bzero(&packet, sizeof(packet)); mndp_hdr = (struct mt_mndp_hdr*)data; memcpy(&(packet.header), mndp_hdr, sizeof(mndp_hdr)); p = data + sizeof(struct mt_mndp_hdr); while(p < data + packet_len) { unsigned short type, len; memcpy(&type, p, 2); memcpy(&len, p + 2, 2); type = ntohs(type); len = ntohs(len); p += 4; /* Check if len is invalid */ if (p + len > data + packet_len) { break; } switch (type) { case MT_MNDPTYPE_ADDRESS: if (len >= ETH_ALEN) { memcpy(packet.address, p, ETH_ALEN); } break; case MT_MNDPTYPE_IDENTITY: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packet.identity, p, len); packet.identity[len] = '\0'; break; case MT_MNDPTYPE_PLATFORM: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packet.platform, p, len); packet.platform[len] = '\0'; break; case MT_MNDPTYPE_VERSION: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packet.version, p, len); packet.version[len] = '\0'; break; case MT_MNDPTYPE_TIMESTAMP: memcpy(&(packet.uptime), p, 4); /* Seems like ping uptime is transmitted as little endian? */ packet.uptime = le32toh(packet.uptime); break; case MT_MNDPTYPE_HARDWARE: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packet.hardware, p, len); packet.hardware[len] = '\0'; break; case MT_MNDPTYPE_SOFTID: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packet.softid, p, len); packet.softid[len] = '\0'; break; /*default: Unhandled MNDP type */ } p += len; } return &packet; } int query_mndp(const char *identity, unsigned char *mac) { int fastlookup = 0; int sock, length; int optval = 1; struct sockaddr_in si_me, si_remote; unsigned char buff[MT_PACKET_LEN]; unsigned int message = 0; struct timeval timeout; time_t start_time; fd_set read_fds; struct mt_mndp_info *packet; start_time = time(0); /* Open a UDP socket handle */ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Allow to share socket */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); /* Set initialize address/port */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MNDP_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to specified address/port */ if (bind(sock, (struct sockaddr *)&si_me, sizeof(si_me)) == -1) { fprintf(stderr, _("Error binding to %s:%d\n"), inet_ntoa(si_me.sin_addr), MT_MNDP_PORT); close(sock); return 0; } /* Set the socket to allow sending broadcast packets */ setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)); /* Request routers identify themselves */ memset((char *) &si_remote, 0, sizeof(si_remote)); si_remote.sin_family = AF_INET; si_remote.sin_port = htons(MT_MNDP_PORT); si_remote.sin_addr.s_addr = htonl(INADDR_BROADCAST); if (sendto(sock, &message, sizeof (message), 0, (struct sockaddr *)&si_remote, sizeof(si_remote)) == -1) { fprintf(stderr, _("Unable to send broadcast packet: Router lookup will be slow\n")); fastlookup = 0; } else { fastlookup = 1; } while (1) { /* Timeout, in case we receive a lot of packets, but from the wrong routers */ if (time(0) - start_time > (fastlookup ? MT_MNDP_TIMEOUT : MT_MNDP_LONGTIMEOUT)) { goto done; } FD_ZERO(&read_fds); FD_SET(sock, &read_fds); timeout.tv_sec = fastlookup ? MT_MNDP_TIMEOUT : MT_MNDP_LONGTIMEOUT; timeout.tv_usec = 0; select(sock + 1, &read_fds, NULL, NULL, &timeout); if (!FD_ISSET(sock, &read_fds)) { goto done; } /* Read UDP packet */ length = recvfrom(sock, buff, MT_PACKET_LEN, 0, 0, 0); if (length < 0) { goto done; } /* Parse MNDP packet */ packet = parse_mndp(buff, length); if (packet != NULL) { if (strcasecmp(identity, packet->identity) == 0) { memcpy(mac, packet->address, ETH_ALEN); close(sock); return 1; } } } done: close(sock); return 0; } /* * This function accepts either a full MAC address using : or - as seperators. * Or a router hostname. The hostname will be searched for via MNDP broadcast packets. */ int query_mndp_or_mac(char *address, unsigned char *dstmac, int verbose) { char *p = address; int colons = 0; int dashs = 0; while (*p++) { if (*p == ':') { colons++; } else if (*p == '-') { dashs++; } } /* * Windows users often enter macs with dash instead * of colon. */ if (colons == 0 && dashs == 5) { p = address; while (*p++) { if (*p == '-') { *p = ':'; } } colons = dashs; } if (colons != 5) { /* * Not a valid mac-address. * Search for Router by identity name, using MNDP */ if (verbose) { fprintf(stderr, _("Searching for '%s'..."), address); } if (!query_mndp(address, dstmac)) { if (verbose) { fprintf(stderr, _("not found\n")); } return 0; } /* Router found, display mac and continue */ if (verbose) { fprintf(stderr, _("found\n")); } } else { /* Convert mac address string to ether_addr struct */ ether_aton_r(address, (struct ether_addr *)dstmac); } return 1; } mactelnet-0.4.0/mndp.h0000664000000000000000000000007012001345061013263 0ustar rootroot#ifndef _MNDP_H #define _MNDP_H int mndp(void); #endifmactelnet-0.4.0/docs/0000775000000000000000000000000012001345061013107 5ustar rootrootmactelnet-0.4.0/docs/mndp.10000664000000000000000000000121612001345061014127 0ustar rootroot.TH MNDP 1 "February 27, 2011" .SH NAME mndp \- A tool for discovering other RouterOS or mactelnetd devices .SH SYNOPSIS .B mndp .SH DESCRIPTION This tool enables you to discover RouterOS or MAC-Telnetd enabled devices. It will display the MAC-address software version, and uptime of every device or machine it discovers. .PP To exit this application, use .B Control + C \. .SH SEE ALSO .BR mactelnet (1), .BR macping (1), .BR mactelnetd (1). .SH AUTHOR mndp was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.0/docs/macping.10000664000000000000000000000236012001345061014610 0ustar rootroot.TH MACPING 1 "February 27, 2011" .SH NAME macping \- A tool for pinging other RouterOS or mactelnetd devices .SH SYNOPSIS .B mactelnet .RI [ options ] " " < MAC-Address | hostname > .SH DESCRIPTION This tool enables you to ping other RouterOS or MAC-Telnetd enabled devices. You can ping either a hostname or a MAC address. If specified, the hostname (identity) will be looked up via MNDP discovery. .SH OPTIONS These programs follow the usual GNU command line syntax. A summary of options is included below. .TP .B \-f Fast mode, do not wait before sending next ping request. The next ping will be sent immediately when the last ping is received. This cannot be used with .B -c 0 \. .TP .B \-s Specify the amount of bytes to send in each ping packet, up to ~1400 bytes. .TP .B \-c Number of packets to send before exiting. A value of .B 0 means unlimited packets and the tool must be exited with Control + C. .TP .B \-h Show summary of options. .TP .B \-v Show version of program. .SH SEE ALSO .BR mndp (1), .BR mactelnet (1), .BR mactelnetd (1). .SH AUTHOR macping was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.0/docs/mactelnet.10000664000000000000000000000322212001345061015144 0ustar rootroot.TH MACTELNET 1 "February 27, 2011" .SH NAME mactelnet \- A tool for telneting via MAC addresses .SH SYNOPSIS .B mactelnet .RI [ options ] " " < MAC-Address | hostname > .SH DESCRIPTION This tool enables you to telnet other RouterOS or MAC-Telnetd enabled devices. You can connect to either a hostname or a MAC address. If specified, the hostname (identity) will be looked up via MNDP discovery. .SH OPTIONS These programs follow the usual GNU command line syntax. A summary of options is included below. .TP .B \-l This will discover RouterOS or MAC-Telnetd enabled devices. It will list the MAC-address software version, and uptime of every device or machine it discovers. To exit the discovery, use .B Control + C \. .TP .B \-n Do not use broadcast packets. A tad less insecure but requires root privileges. This means that ethernet packets will have the specified mac-address as the packet destination, instead of using the ethernet broadcast address. .TP .B \-t Amount of seconds to wait for a response on each interface. If you have several network interfaces, this is the timeout value per interface. .TP .B \-u Specify username. Without this option, you will need to enter the username in a interactive prompt. .TP .B \-p Specify password. Without this option, you will need to enter the password in a interactive prompt. .TP .B \-h Show summary of options. .TP .B \-v Show version of program. .SH SEE ALSO .BR mndp (1), .BR mactelnetd (1), .BR macping (1). .SH AUTHOR mactelnet was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.0/docs/mactelnetd.10000664000000000000000000000233712001345061015316 0ustar rootroot.TH MACTELNETD 1 "February 27, 2011" .SH NAME mactelnetd \- Telnet daemon for MAC-address connections .SH SYNOPSIS .B mactelnetd .RI [ options ] .SH DESCRIPTION This daemon listens for telnet connections from Mikrotik RouterOS devices or mactelnet clients on the same physical network. It also announces it's hostname via the MNDP protocol every minute. .SH OPTIONS These programs follow the usual GNU command line syntax. A summary of options is included below. .TP .B \-n Do not use broadcast packets. A tad less insecure. This means that ethernet packets will have the mac-address of the client as the packet destination, instead of using the ethernet broadcast address. .TP .B \-h Show summary of options. .TP .B \-v Show version of program. .SH FILES .TP .B /etc/mactelnetd.users This file contains a line separated list of users that will have access to your machine. Usernames and passwords are separated by colon. This file is read each time a user connects. .SH SEE ALSO .BR mndp (1), .BR mactelnet (1), .BR macping (1). .SH AUTHOR mactelnetd was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.0/mndp.c0000664000000000000000000000757412001345061013276 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "protocol.h" #include "config.h" #define _(String) gettext (String) /* This file is also used for the -l option in mactelnet */ #ifndef FROM_MACTELNET /* Protocol data direction, not used here, but obligatory for protocol.c */ unsigned char mt_direction_fromserver = 0; int main(int argc, char **argv) { #else int mndp(void) { #endif int sock,result; int optval = 1; struct sockaddr_in si_me, si_remote; unsigned char buff[MT_PACKET_LEN]; #ifdef FROM_MACTELNET /* mactelnet.c has this set to 1 */ mt_direction_fromserver = 0; #endif setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); /* Open a UDP socket handle */ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Set initialize address/port */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MNDP_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to specified address/port */ if (bind(sock, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d\n"), inet_ntoa(si_me.sin_addr), MT_MNDP_PORT); return 1; } /* Write informative message to STDERR to make it easier to use the output in simple scripts */ fprintf(stderr, _("Searching for MikroTik routers... Abort with CTRL+C.\n")); /* Set the socket to allow sending broadcast packets */ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval))==-1) { fprintf(stderr, _("Unable to send broadcast packets: Operating in receive only mode.\n")); } else { /* Request routers identify themselves */ unsigned int message = 0; memset((char *) &si_remote, 0, sizeof(si_remote)); si_remote.sin_family = AF_INET; si_remote.sin_port = htons(MT_MNDP_PORT); si_remote.sin_addr.s_addr = htonl(INADDR_BROADCAST); if (sendto (sock, &message, sizeof (message), 0, (struct sockaddr *)&si_remote, sizeof(si_remote))==-1) { fprintf(stderr, _("Unable to send broadcast packet: Operating in receive only mode.\n")); } } printf("\n\E[1m%-17s %s\E[m\n", _("MAC-Address"), _("Identity (platform version hardware) uptime")); while(1) { struct mt_mndp_info *packet; /* Wait for a UDP packet */ result = recvfrom(sock, buff, MT_PACKET_LEN, 0, 0, 0); if (result < 0) { fprintf(stderr, _("An error occured. aborting\n")); exit(1); } /* Parse MNDP packet */ packet = parse_mndp(buff, result); if (packet != NULL) { /* Print it */ printf("%-17s %s", ether_ntoa((struct ether_addr *)packet->address), packet->identity); if (packet->platform != NULL) { printf(" (%s %s %s)", packet->platform, packet->version, packet->hardware); } if (packet->uptime > 0) { printf(_(" up %d days %d hours"), packet->uptime / 86400, packet->uptime % 86400 / 3600); } putchar('\n'); } } /* We'll never get here.. */ return 0; } mactelnet-0.4.0/config.h0000664000000000000000000000323412001345061013577 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _CONFIG_H #define _CONFIG_H 1 #define DEBUG 0 #define PROGRAM_VERSION "0.4.0" #if defined(__APPLE__) && defined(__MACH__) #define PLATFORM_NAME "Mac OS X" #elif defined(__FreeBSD__) #define PLATFORM_NAME "FreeBSD" #elif defined(__NetBSD__) #define PLATFORM_NAME "NetBSD" #elif defined(__OpenBSD__) #define PLATFORM_NAME "OpenBSD" #elif defined(__MINT__) #define PLATFORM_NAME "FreeMiNT" #elif defined(__bsdi__) #define PLATFORM_NAME "BSD/OS" #elif defined(linux) || defined(__linux__) #define PLATFORM_NAME "Linux" #elif defined(sun) #define PLATFORM_NAME "Solaris" #elif defined(__hpux) #define PLATFORM_NAME "HPUX" #elif defined(__riscos__) #define PLATFORM_NAME "RISC OS" #elif defined(__FreeBSD_kernel__) #define PLATFORM_NAME "kFreeBSD" #else #define PLATFORM_NAME "Unknown" #endif #endif mactelnet-0.4.0/mactelnetd.c0000664000000000000000000007723412001345061014460 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _XOPEN_SOURCE 600 #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #else #include #endif #include #include #include #include #include #include #include #include "md5.h" #include "protocol.h" #include "console.h" #include "interfaces.h" #include "users.h" #include "config.h" #define PROGRAM_NAME "MAC-Telnet Daemon" #define MAX_INSOCKETS 100 #define MT_INTERFACE_LEN 128 /* Max ~5 pings per second */ #define MT_MAXPPS MT_MNDP_BROADCAST_INTERVAL * 5 #define _(String) gettext (String) #define gettext_noop(String) String static int sockfd; static int insockfd; static int mndpsockfd; static int pings = 0; struct net_interface interfaces[MAX_INTERFACES]; static int use_raw_socket = 0; static struct in_addr sourceip; static struct in_addr destip; static int sourceport; static time_t last_mndp_time = 0; /* Protocol data direction */ unsigned char mt_direction_fromserver = 1; /* Anti-timeout is every 10 seconds. Give up after 15. */ #define MT_CONNECTION_TIMEOUT 15 /* Connection states */ enum mt_connection_state { STATE_AUTH, STATE_CLOSED, STATE_ACTIVE }; /** Connection struct */ struct mt_connection { struct net_interface *interface; char interface_name[256]; unsigned short seskey; unsigned int incounter; unsigned int outcounter; time_t lastdata; int terminal_mode; enum mt_connection_state state; int ptsfd; int slavefd; int pid; int wait_for_ack; int have_enckey; char username[30]; unsigned char trypassword[17]; unsigned char srcip[IPV4_ALEN]; unsigned char srcmac[ETH_ALEN]; unsigned short srcport; unsigned char dstmac[ETH_ALEN]; unsigned char enckey[16]; unsigned short terminal_width; unsigned short terminal_height; char terminal_type[30]; struct mt_connection *next; }; static void uwtmp_login(struct mt_connection *); static void uwtmp_logout(struct mt_connection *); static struct mt_connection *connections_head = NULL; static void list_add_connection(struct mt_connection *conn) { struct mt_connection *p; struct mt_connection *last; if (connections_head == NULL) { connections_head = conn; connections_head->next = NULL; return; } for (p = connections_head; p != NULL; p = p->next) {last = p;} last->next = conn; conn->next = NULL; } static void list_remove_connection(struct mt_connection *conn) { struct mt_connection *p; struct mt_connection *last; if (connections_head == NULL) { return; } if (conn->state == STATE_ACTIVE && conn->ptsfd > 0) { close(conn->ptsfd); } if (conn->state == STATE_ACTIVE && conn->slavefd > 0) { close(conn->slavefd); } uwtmp_logout(conn); if (connections_head == conn) { connections_head = conn->next; free(conn); return; } for (p = connections_head; p != NULL; p = p->next) { if (p == conn) { last->next = p->next; free(p); return; } last = p; } } static struct mt_connection *list_find_connection(unsigned short seskey, unsigned char *srcmac) { struct mt_connection *p; if (connections_head == NULL) { return NULL; } for (p = connections_head; p != NULL; p = p->next) { if (p->seskey == seskey && memcmp(srcmac, p->srcmac, ETH_ALEN) == 0) { return p; } } return NULL; } static int find_socket(unsigned char *mac) { int i; for (i = 0; i < MAX_INTERFACES; ++i) { if (interfaces[i].in_use && memcmp(mac, interfaces[i].mac_addr, ETH_ALEN) == 0) { return i; } if (!interfaces[i].in_use) { break; } } return -1; } static void setup_sockets() { int i; for (i = 0; i < MAX_INTERFACES; ++i) { int optval = 1; struct sockaddr_in si_me; struct ether_addr *mac = (struct ether_addr *)&(interfaces[i].mac_addr); if (interfaces[i].in_use == 0 || !interfaces[i].has_mac) { continue; } if (!use_raw_socket) { interfaces[i].socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (interfaces[i].socketfd < 0) { continue; } if (setsockopt(interfaces[i].socketfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval))==-1) { perror("SO_BROADCAST"); continue; } setsockopt(interfaces[i].socketfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); /* Initialize receiving socket on the device chosen */ si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MACTELNET_PORT); memcpy(&(si_me.sin_addr.s_addr), interfaces[i].ipv4_addr, IPV4_ALEN); if (bind(interfaces[i].socketfd, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d, %s\n"), inet_ntoa(si_me.sin_addr), sourceport, strerror(errno)); continue; } } syslog(LOG_NOTICE, _("Listening on %s for %s\n"), interfaces[i].name, ether_ntoa(mac)); } } static int send_udp(const struct mt_connection *conn, const struct mt_packet *packet) { if (use_raw_socket) { return net_send_udp(sockfd, conn->interface, conn->dstmac, conn->srcmac, &sourceip, sourceport, &destip, conn->srcport, packet->data, packet->size); } else { /* Init SendTo struct */ struct sockaddr_in socket_address; socket_address.sin_family = AF_INET; socket_address.sin_port = htons(conn->srcport); socket_address.sin_addr.s_addr = htonl(INADDR_BROADCAST); return sendto(conn->interface->socketfd, packet->data, packet->size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); } } static int send_special_udp(struct net_interface *interface, unsigned short port, const struct mt_packet *packet) { unsigned char dstmac[ETH_ALEN]; if (use_raw_socket) { memset(dstmac, 0xff, ETH_ALEN); return net_send_udp(sockfd, interface, interface->mac_addr, dstmac, (const struct in_addr *)&interface->ipv4_addr, port, &destip, port, packet->data, packet->size); } else { /* Init SendTo struct */ struct sockaddr_in socket_address; socket_address.sin_family = AF_INET; socket_address.sin_port = htons(port); socket_address.sin_addr.s_addr = htonl(INADDR_BROADCAST); return sendto(interface->socketfd, packet->data, packet->size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); } } static void display_motd() { FILE *fp; int c; if ((fp = fopen("/etc/motd", "r"))) { while ((c = getc(fp)) != EOF) { putchar(c); } fclose(fp); } } static void display_nologin() { FILE *fp; int c; if ((fp = fopen(_PATH_NOLOGIN, "r"))) { while ((c = getc(fp)) != EOF) { putchar(c); } fclose(fp); } } static void uwtmp_login(struct mt_connection *conn) { struct utmp utent; pid_t pid; pid = getpid(); char *line = ttyname(conn->slavefd); if (strncmp(line, "/dev/", 5) == 0) { line += 5; } /* Setup utmp struct */ memset((void *) &utent, 0, sizeof(utent)); utent.ut_type = USER_PROCESS; utent.ut_pid = pid; strncpy(utent.ut_user, conn->username, sizeof(utent.ut_user)); strncpy(utent.ut_line, line, sizeof(utent.ut_line)); strncpy(utent.ut_id, utent.ut_line + 3, sizeof(utent.ut_id)); strncpy(utent.ut_host, ether_ntoa((const struct ether_addr *)conn->srcmac), sizeof(utent.ut_host)); time((time_t *)&(utent.ut_time)); /* Update utmp and/or wtmp */ setutent(); pututline(&utent); endutent(); updwtmp(_PATH_WTMP, &utent); } static void uwtmp_logout(struct mt_connection *conn) { if (conn->pid > 0) { struct utmp *utentp; struct utmp utent; setutent(); while ((utentp = getutent()) != NULL) { if (utentp->ut_pid == conn->pid && utentp->ut_id) { break; } } if (utentp) { utent = *utentp; utent.ut_type = DEAD_PROCESS; utent.ut_tv.tv_sec = time(NULL); pututline(&utent); endutent(); updwtmp(_PATH_WTMP, &utent); } } } static void abort_connection(struct mt_connection *curconn, struct mt_mactelnet_hdr *pkthdr, char *message) { struct mt_packet pdata; init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, message, strlen(message)); send_udp(curconn, &pdata); /* Make connection time out; lets the previous message get acked before disconnecting */ curconn->state = STATE_CLOSED; init_packet(&pdata, MT_PTYPE_END, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); send_udp(curconn, &pdata); } static void user_login(struct mt_connection *curconn, struct mt_mactelnet_hdr *pkthdr) { struct mt_packet pdata; unsigned char md5sum[17]; char md5data[100]; struct mt_credentials *user; char *slavename; /* Reparse user file before each login */ read_userfile(); if ((user = find_user(curconn->username)) != NULL) { md5_state_t state; /* Concat string of 0 + password + encryptionkey */ md5data[0] = 0; strncpy(md5data + 1, user->password, 82); memcpy(md5data + 1 + strlen(user->password), curconn->enckey, 16); /* Generate md5 sum of md5data with a leading 0 */ md5_init(&state); md5_append(&state, (const md5_byte_t *)md5data, strlen(user->password) + 17); md5_finish(&state, (md5_byte_t *)md5sum + 1); md5sum[0] = 0; init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); curconn->outcounter += add_control_packet(&pdata, MT_CPTYPE_END_AUTH, NULL, 0); send_udp(curconn, &pdata); if (curconn->state == STATE_ACTIVE) { return; } } if (user == NULL || memcmp(md5sum, curconn->trypassword, 17) != 0) { syslog(LOG_NOTICE, _("(%d) Invalid login by %s."), curconn->seskey, curconn->username); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Login failed, incorrect username or password\r\n")); /* TODO: should wait some time (not with sleep) before returning, to minimalize brute force attacks */ return; } /* User is logged in */ curconn->state = STATE_ACTIVE; /* Enter terminal mode */ curconn->terminal_mode = 1; /* Open pts handle */ curconn->ptsfd = posix_openpt(O_RDWR); if (curconn->ptsfd == -1 || grantpt(curconn->ptsfd) == -1 || unlockpt(curconn->ptsfd) == -1) { syslog(LOG_ERR, "posix_openpt: %s", strerror(errno)); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Terminal error\r\n")); return; } /* Get file path for our pts */ slavename = ptsname(curconn->ptsfd); if (slavename != NULL) { pid_t pid; struct stat sb; struct passwd *user = (struct passwd *)getpwnam(curconn->username); if (user == NULL) { syslog(LOG_WARNING, _("(%d) Login ok, but local user not accessible (%s)."), curconn->seskey, curconn->username); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Local user not accessible\r\n")); return; } /* Change the owner of the slave pts */ chown(slavename, user->pw_uid, user->pw_gid); curconn->slavefd = open(slavename, O_RDWR); if (curconn->slavefd == -1) { syslog(LOG_ERR, _("Error opening %s: %s"), slavename, strerror(errno)); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Error opening terminal\r\n")); list_remove_connection(curconn); return; } if ((pid = fork()) == 0) { int i; /* Add login information to utmp/wtmp */ uwtmp_login(curconn); syslog(LOG_INFO, _("(%d) User %s logged in."), curconn->seskey, curconn->username); /* Initialize terminal environment */ setenv("USER", user->pw_name, 1); setenv("HOME", user->pw_dir, 1); setenv("SHELL", user->pw_shell, 1); setenv("TERM", curconn->terminal_type, 1); close(sockfd); close(insockfd); for (i = 0; i < MAX_INTERFACES; ++i) { if (interfaces[i].in_use && interfaces[i].socketfd > 0) { close(interfaces[i].socketfd); } if (!interfaces[i].in_use) { break; } } setsid(); /* Don't let shell process inherit slavefd */ fcntl (curconn->slavefd, F_SETFD, FD_CLOEXEC); close(curconn->ptsfd); /* Redirect STDIN/STDIO/STDERR */ close(0); dup(curconn->slavefd); close(1); dup(curconn->slavefd); close(2); dup(curconn->slavefd); /* Set controlling terminal */ ioctl(0, TIOCSCTTY, 1); tcsetpgrp(0, getpid()); /* Set user id/group id */ if ((setgid(user->pw_gid) != 0) || (setuid(user->pw_uid) != 0)) { syslog(LOG_ERR, _("(%d) Could not log in %s (%d:%d): setuid/setgid: %s"), curconn->seskey, curconn->username, user->pw_uid, user->pw_gid, strerror(errno)); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Internal error\r\n")); exit(0); } /* Abort login if /etc/nologin exists */ if (stat(_PATH_NOLOGIN, &sb) == 0 && getuid() != 0) { syslog(LOG_NOTICE, _("(%d) User %s disconnected with " _PATH_NOLOGIN " message."), curconn->seskey, curconn->username); display_nologin(); curconn->state = STATE_CLOSED; init_packet(&pdata, MT_PTYPE_END, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); send_udp(curconn, &pdata); exit(0); } /* Display MOTD */ display_motd(); chdir(user->pw_dir); /* Spawn shell */ /* TODO: Maybe use "login -f USER" instead? renders motd and executes shell correctly for system */ execl(user->pw_shell, "-", (char *) 0); exit(0); // just to be sure. } close(curconn->slavefd); curconn->pid = pid; set_terminal_size(curconn->ptsfd, curconn->terminal_width, curconn->terminal_height); } } static void handle_data_packet(struct mt_connection *curconn, struct mt_mactelnet_hdr *pkthdr, int data_len) { struct mt_mactelnet_control_hdr cpkt; struct mt_packet pdata; unsigned char *data = pkthdr->data; int got_user_packet = 0; int got_pass_packet = 0; int got_width_packet = 0; int got_height_packet = 0; int success; /* Parse first control packet */ success = parse_control_packet(data, data_len - MT_HEADER_LEN, &cpkt); while (success) { if (cpkt.cptype == MT_CPTYPE_BEGINAUTH) { int plen,i; if (!curconn->have_enckey) { for (i = 0; i < 16; ++i) { curconn->enckey[i] = rand() % 256; } curconn->have_enckey = 1; memset(curconn->trypassword, 0, sizeof(curconn->trypassword)); } init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); plen = add_control_packet(&pdata, MT_CPTYPE_ENCRYPTIONKEY, (curconn->enckey), 16); curconn->outcounter += plen; send_udp(curconn, &pdata); } else if (cpkt.cptype == MT_CPTYPE_USERNAME) { memcpy(curconn->username, cpkt.data, cpkt.length > 29 ? 29 : cpkt.length); curconn->username[cpkt.length > 29 ? 29 : cpkt.length] = 0; got_user_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_WIDTH) { unsigned short width; memcpy(&width, cpkt.data, 2); curconn->terminal_width = le16toh(width); got_width_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_HEIGHT) { unsigned short height; memcpy(&height, cpkt.data, 2); curconn->terminal_height = le16toh(height); got_height_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_TYPE) { memcpy(curconn->terminal_type, cpkt.data, cpkt.length > 29 ? 29 : cpkt.length); curconn->terminal_type[cpkt.length > 29 ? 29 : cpkt.length] = 0; } else if (cpkt.cptype == MT_CPTYPE_PASSWORD) { memcpy(curconn->trypassword, cpkt.data, 17); got_pass_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_PLAINDATA) { /* relay data from client to shell */ if (curconn->state == STATE_ACTIVE && curconn->ptsfd != -1) { write(curconn->ptsfd, cpkt.data, cpkt.length); } } else { syslog(LOG_WARNING, _("(%d) Unhandeled control packet type: %d"), curconn->seskey, cpkt.cptype); } /* Parse next control packet */ success = parse_control_packet(NULL, 0, &cpkt); } if (got_user_packet && got_pass_packet) { user_login(curconn, pkthdr); } if (curconn->state == STATE_ACTIVE && (got_width_packet || got_height_packet)) { set_terminal_size(curconn->ptsfd, curconn->terminal_width, curconn->terminal_height); } } static void handle_packet(unsigned char *data, int data_len, const struct sockaddr_in *address) { struct mt_mactelnet_hdr pkthdr; struct mt_connection *curconn = NULL; struct mt_packet pdata; int interface_index; parse_packet(data, &pkthdr); /* Drop packets not belonging to us */ if ((interface_index = find_socket(pkthdr.dstaddr)) < 0) { return; } switch (pkthdr.ptype) { case MT_PTYPE_PING: if (pings++ > MT_MAXPPS) { break; } init_pongpacket(&pdata, (unsigned char *)&(pkthdr.dstaddr), (unsigned char *)&(pkthdr.srcaddr)); add_packetdata(&pdata, pkthdr.data - 4, data_len - (MT_HEADER_LEN - 4)); { if (index >= 0) { send_special_udp(&interfaces[interface_index], MT_MACTELNET_PORT, &pdata); } } break; case MT_PTYPE_SESSIONSTART: syslog(LOG_DEBUG, _("(%d) New connection from %s."), pkthdr.seskey, ether_ntoa((struct ether_addr*)&(pkthdr.srcaddr))); curconn = calloc(1, sizeof(struct mt_connection)); curconn->seskey = pkthdr.seskey; curconn->lastdata = time(NULL); curconn->state = STATE_AUTH; curconn->interface = &interfaces[interface_index]; strncpy(curconn->interface_name, interfaces[interface_index].name, 254); curconn->interface_name[255] = '\0'; memcpy(curconn->srcmac, pkthdr.srcaddr, ETH_ALEN); memcpy(curconn->srcip, &(address->sin_addr), IPV4_ALEN); curconn->srcport = htons(address->sin_port); memcpy(curconn->dstmac, pkthdr.dstaddr, ETH_ALEN); list_add_connection(curconn); init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); break; case MT_PTYPE_END: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn == NULL) { break; } if (curconn->state != STATE_CLOSED) { init_packet(&pdata, MT_PTYPE_END, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } syslog(LOG_DEBUG, _("(%d) Connection closed."), curconn->seskey); list_remove_connection(curconn); return; case MT_PTYPE_ACK: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn == NULL) { break; } if (pkthdr.counter <= curconn->outcounter) { curconn->wait_for_ack = 0; } if (time(0) - curconn->lastdata > 9) { // Answer to anti-timeout packet init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } curconn->lastdata = time(NULL); return; case MT_PTYPE_DATA: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn == NULL) { break; } curconn->lastdata = time(NULL); /* ack the data packet */ init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter + (data_len - MT_HEADER_LEN)); send_udp(curconn, &pdata); /* Accept first packet, and all packets greater than incounter, and if counter has wrapped around. */ if (curconn->incounter == 0 || pkthdr.counter > curconn->incounter || (curconn->incounter - pkthdr.counter) > 16777216) { curconn->incounter = pkthdr.counter; } else { /* Ignore double or old packets */ return; } handle_data_packet(curconn, &pkthdr, data_len); break; default: if (curconn) { syslog(LOG_WARNING, _("(%d) Unhandeled packet type: %d"), curconn->seskey, pkthdr.ptype); init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } } if (0 && curconn != NULL) { printf("Packet, incounter %d, outcounter %d\n", curconn->incounter, curconn->outcounter); } } static void daemonize() { int pid,fd; pid = fork(); /* Error? */ if (pid < 0) { exit(1); } /* Parent exit */ if (pid > 0) { exit(0); } setsid(); close(0); close(1); close(2); fd = open("/dev/null",O_RDWR); dup(fd); dup(fd); } static void print_version() { fprintf(stderr, PROGRAM_NAME " " PROGRAM_VERSION "\n"); } void mndp_broadcast() { struct mt_packet pdata; struct utsname s_uname; int i; unsigned int uptime; #ifdef __linux__ struct sysinfo s_sysinfo; if (sysinfo(&s_sysinfo) != 0) { return; } /* Seems like ping uptime is transmitted as little endian? */ uptime = htole32(s_sysinfo.uptime); #else struct timespec ts; if (clock_gettime(CLOCK_UPTIME, &ts) != -1) { uptime = htole32(((unsigned int)ts.tv_sec)); } #endif if (uname(&s_uname) != 0) { return; } for (i = 0; i < MAX_INTERFACES; ++i) { struct net_interface *interface = &interfaces[i]; struct mt_mndp_hdr *header = (struct mt_mndp_hdr *)&(pdata.data); if (interfaces[i].has_mac == 0) { continue; } if (interfaces[i].in_use == 0) { break; } mndp_init_packet(&pdata, 0, 1); mndp_add_attribute(&pdata, MT_MNDPTYPE_ADDRESS, interface->mac_addr, ETH_ALEN); mndp_add_attribute(&pdata, MT_MNDPTYPE_IDENTITY, s_uname.nodename, strlen(s_uname.nodename)); mndp_add_attribute(&pdata, MT_MNDPTYPE_VERSION, s_uname.release, strlen(s_uname.release)); mndp_add_attribute(&pdata, MT_MNDPTYPE_PLATFORM, PLATFORM_NAME, strlen(PLATFORM_NAME)); mndp_add_attribute(&pdata, MT_MNDPTYPE_HARDWARE, s_uname.machine, strlen(s_uname.machine)); mndp_add_attribute(&pdata, MT_MNDPTYPE_TIMESTAMP, &uptime, 4); header->cksum = in_cksum((unsigned short *)&(pdata.data), pdata.size); send_special_udp(interface, MT_MNDP_PORT, &pdata); } } void sigterm_handler() { struct mt_connection *p; struct mt_packet pdata; /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ char message[] = gettext_noop("\r\n\r\nDaemon shutting down.\r\n"); syslog(LOG_NOTICE, _("Daemon shutting down")); for (p = connections_head; p != NULL; p = p->next) { if (p->state == STATE_ACTIVE) { init_packet(&pdata, MT_PTYPE_DATA, p->interface->mac_addr, p->srcmac, p->seskey, p->outcounter); add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, _(message), strlen(_(message))); send_udp(p, &pdata); init_packet(&pdata, MT_PTYPE_END, p->interface->mac_addr, p->srcmac, p->seskey, p->outcounter); send_udp(p, &pdata); } } /* Doesn't hurt to tidy up */ close(sockfd); close(insockfd); if (!use_raw_socket) { int i; for (i = 0; i < MAX_INTERFACES; ++i) { if (interfaces[i].in_use && interfaces[i].socketfd > 0) close(interfaces[i].socketfd); } } closelog(); exit(0); } void sighup_handler() { int i; struct mt_connection *p; syslog(LOG_NOTICE, _("SIGHUP: Reloading interfaces")); if (!use_raw_socket) { for (i = 0; i < MAX_INTERFACES; ++i) { close(interfaces[i].socketfd); } } bzero(interfaces, sizeof(interfaces)); if (net_get_interfaces(interfaces, MAX_INTERFACES) <= 0) { syslog(LOG_ERR, _("No devices found! Exiting.\n")); exit(1); } setup_sockets(); /* Reassign outgoing interfaces to connections again, since they may have changed */ for (p = connections_head; p != NULL; p = p->next) { if (p->interface_name != NULL) { struct net_interface *interface = net_get_interface_ptr(interfaces, MAX_INTERFACES, p->interface_name, 0); if (interface != NULL) { p->interface = interface; } else { struct mt_connection tmp; syslog(LOG_NOTICE, _("(%d) Connection closed because interface %s is gone."), p->seskey, p->interface_name); tmp.next = p->next; list_remove_connection(p); p = &tmp; } } } } /* * TODO: Rewrite main() when all sub-functionality is tested */ int main (int argc, char **argv) { int result,i; struct sockaddr_in si_me; struct sockaddr_in si_me_mndp; struct timeval timeout; struct mt_packet pdata; fd_set read_fds; int c,optval = 1; int print_help = 0; int foreground = 0; int interface_count = 0; setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); while ((c = getopt(argc, argv, "fnvh?")) != -1) { switch (c) { case 'f': foreground = 1; break; case 'n': use_raw_socket = 1; break; case 'v': print_version(); exit(0); break; case 'h': case '?': print_help = 1; break; } } if (print_help) { print_version(); fprintf(stderr, _("Usage: %s [-f|-n|-h]\n"), argv[0]); if (print_help) { fprintf(stderr, _("\nParameters:\n" " -f Run process in foreground.\n" " -n Do not use broadcast packets. Just a tad less insecure.\n" " -h This help.\n" "\n")); } return 1; } if (geteuid() != 0) { fprintf(stderr, _("You need to have root privileges to use %s.\n"), argv[0]); return 1; } /* Try to read user file */ read_userfile(); /* Seed randomizer */ srand(time(NULL)); if (use_raw_socket) { /* Transmit raw packets with this socket */ sockfd = net_init_raw_socket(); } /* Receive regular udp packets with this socket */ insockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (insockfd < 0) { perror("insockfd"); return 1; } /* Set source port */ sourceport = MT_MACTELNET_PORT; /* Listen address*/ inet_pton(AF_INET, (char *)"0.0.0.0", &sourceip); /* Set up global info about the connection */ inet_pton(AF_INET, (char *)"255.255.255.255", &destip); /* Initialize receiving socket on the device chosen */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(sourceport); memcpy(&(si_me.sin_addr), &sourceip, IPV4_ALEN); setsockopt(insockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to udp port */ if (bind(insockfd, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d, %s\n"), inet_ntoa(si_me.sin_addr), sourceport, strerror(errno)); return 1; } /* TODO: Move socket initialization out of main() */ /* Receive mndp udp packets with this socket */ mndpsockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (mndpsockfd < 0) { perror("mndpsockfd"); return 1; } memset((char *)&si_me_mndp, 0, sizeof(si_me_mndp)); si_me_mndp.sin_family = AF_INET; si_me_mndp.sin_port = htons(MT_MNDP_PORT); memcpy(&(si_me_mndp.sin_addr), &sourceip, IPV4_ALEN); setsockopt(mndpsockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to udp port */ if (bind(mndpsockfd, (struct sockaddr *)&si_me_mndp, sizeof(si_me_mndp))==-1) { fprintf(stderr, _("MNDP: Error binding to %s:%d, %s\n"), inet_ntoa(si_me_mndp.sin_addr), MT_MNDP_PORT, strerror(errno)); } openlog("mactelnetd", LOG_PID, LOG_DAEMON); syslog(LOG_NOTICE, _("Bound to %s:%d"), inet_ntoa(si_me.sin_addr), sourceport); /* Enumerate available interfaces */ net_get_interfaces(interfaces, MAX_INTERFACES); setup_sockets(); if (!foreground) { daemonize(); } /* Handle zombies etc */ signal(SIGCHLD,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); for (i = 0; i < MAX_INTERFACES; ++i) { if (interfaces[i].in_use && interfaces[i].has_mac) { interface_count++; } } if (interface_count == 0) { syslog(LOG_ERR, _("Unable to find any valid network interfaces\n")); exit(1); } while (1) { int reads; struct mt_connection *p; int maxfd=0; time_t now; /* Init select */ FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); FD_SET(mndpsockfd, &read_fds); maxfd = insockfd > mndpsockfd ? insockfd : mndpsockfd; /* Add active connections to select queue */ for (p = connections_head; p != NULL; p = p->next) { if (p->state == STATE_ACTIVE && p->wait_for_ack == 0 && p->ptsfd > 0) { FD_SET(p->ptsfd, &read_fds); if (p->ptsfd > maxfd) { maxfd = p->ptsfd; } } } timeout.tv_sec = 1; timeout.tv_usec = 0; /* Wait for data or timeout */ reads = select(maxfd+1, &read_fds, NULL, NULL, &timeout); if (reads > 0) { /* Handle data from clients TODO: Enable broadcast support (without raw sockets) */ if (FD_ISSET(insockfd, &read_fds)) { unsigned char buff[1500]; struct sockaddr_in saddress; unsigned int slen = sizeof(saddress); result = recvfrom(insockfd, buff, 1500, 0, (struct sockaddr *)&saddress, &slen); handle_packet(buff, result, &saddress); } if (FD_ISSET(mndpsockfd, &read_fds)) { unsigned char buff[1500]; struct sockaddr_in saddress; unsigned int slen = sizeof(saddress); result = recvfrom(mndpsockfd, buff, 1500, 0, (struct sockaddr *)&saddress, &slen); /* Handle MNDP broadcast request, max 1 rps */ if (result == 4 && time(NULL) - last_mndp_time > 0) { mndp_broadcast(); time(&last_mndp_time); } } /* Handle data from terminal sessions */ for (p = connections_head; p != NULL; p = p->next) { /* Check if we have data ready in the pty buffer for the active session */ if (p->state == STATE_ACTIVE && p->ptsfd > 0 && p->wait_for_ack == 0 && FD_ISSET(p->ptsfd, &read_fds)) { unsigned char keydata[1024]; int datalen,plen; /* Read it */ datalen = read(p->ptsfd, &keydata, 1024); if (datalen > 0) { /* Send it */ init_packet(&pdata, MT_PTYPE_DATA, p->dstmac, p->srcmac, p->seskey, p->outcounter); plen = add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, &keydata, datalen); p->outcounter += plen; p->wait_for_ack = 1; result = send_udp(p, &pdata); } else { /* Shell exited */ struct mt_connection tmp; init_packet(&pdata, MT_PTYPE_END, p->dstmac, p->srcmac, p->seskey, p->outcounter); send_udp(p, &pdata); if (p->username != NULL) { syslog(LOG_INFO, _("(%d) Connection to user %s closed."), p->seskey, p->username); } else { syslog(LOG_INFO, _("(%d) Connection closed."), p->seskey); } tmp.next = p->next; list_remove_connection(p); p = &tmp; } } else if (p->state == STATE_ACTIVE && p->ptsfd > 0 && p->wait_for_ack == 1 && FD_ISSET(p->ptsfd, &read_fds)) { printf(_("(%d) Waiting for ack\n"), p->seskey); } } /* Handle select() timeout */ } time(&now); if (now - last_mndp_time > MT_MNDP_BROADCAST_INTERVAL) { pings = 0; mndp_broadcast(); last_mndp_time = now; } if (connections_head != NULL) { struct mt_connection *p,tmp; for (p = connections_head; p != NULL; p = p->next) { if (now - p->lastdata >= MT_CONNECTION_TIMEOUT) { syslog(LOG_INFO, _("(%d) Session timed out"), p->seskey); init_packet(&pdata, MT_PTYPE_DATA, p->dstmac, p->srcmac, p->seskey, p->outcounter); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, _("Timeout\r\n"), 9); send_udp(p, &pdata); init_packet(&pdata, MT_PTYPE_END, p->dstmac, p->srcmac, p->seskey, p->outcounter); send_udp(p, &pdata); tmp.next = p->next; list_remove_connection(p); p = &tmp; } } } } /* Never reached */ return 0; } mactelnet-0.4.0/README.markdown0000664000000000000000000000566712001345061014676 0ustar rootrootMAC-Telnet for Linux ==================== Console tools for connecting to, and serving, devices using MikroTik RouterOS MAC-Telnet protocol. Installation ------------ Then download source tarball, extract, compile and install: wget http://github.com/haakonnessjoen/MAC-Telnet/tarball/master tar zxvf haakonness*.tar.gz cd haakonness*/ make all install Now you're ready. TIP: You can use the well known "expect" tool to automate/script dialogues via mactelnet! Usage ----- # mactelnet -h Usage: mactelnet [-h] [-n] [-t ] [-u ] [-p ] [-U ] | -l Parameters: MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to discover it. identity The identity/name of your destination device. Uses MNDP protocol to find it. -l List/Search for routers nearby. (using MNDP) -n Do not use broadcast packets. Less insecure but requires root privileges. -t Amount of seconds to wait for a response on each interface. -u Specify username on command line. -p Specify password on command line. -U Drop privileges to this user. Used in conjunction with -n for security. -q Quiet mode. -h This help. Example: $ mactelnet 0:c:42:43:58:a5 -u admin Password: Connecting to 0:c:42:43:58:a5...done MMM MMM KKK TTTTTTTTTTT KKK MMMM MMMM KKK TTTTTTTTTTT KKK MMM MMMM MMM III KKK KKK RRRRRR OOOOOO TTT III KKK KKK MMM MM MMM III KKKKK RRR RRR OOO OOO TTT III KKKKK MMM MMM III KKK KKK RRRRRR OOO OOO TTT III KKK KKK MMM MMM III KKK KKK RRR RRR OOOOOO TTT III KKK KKK MikroTik RouterOS 4.0 (c) 1999-2009 http://www.mikrotik.com/ [admin@HMG] > MAC-Ping usage -------------- # macping -h Usage: macping [-h] [-c ] [-s ] Parameters: MAC MAC-Address of the RouterOS/mactelnetd device. -s Specify size of ping packet. -c Number of packets to send. (0 = for ever) -h This help. Example: # macping 0:c:42:43:58:a5 0:c:42:43:58:a5 56 byte, ping time 1.17 ms 0:c:42:43:58:a5 56 byte, ping time 1.07 ms 0:c:42:43:58:a5 56 byte, ping time 1.20 ms 0:c:42:43:58:a5 56 byte, ping time 0.65 ms 0:c:42:43:58:a5 56 byte, ping time 1.19 ms 5 packets transmitted, 5 packets received, 0% packet loss round-trip min/avg/max = 0.65/1.06/1.20 ms Or for use in bash-scripting: # macping 0:c:42:43:58:a5 -c 2 >/dev/null 2>&1 || ( echo "No answer for 2 pings" | mail -s "router down" my.email@address.com ) mactelnet-0.4.0/interfaces.h0000664000000000000000000000335712001345061014463 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _INTERFACES_H #define _INTERFACES_H 1 #define MAX_INTERFACES 32 struct net_interface { char name[256]; unsigned char ipv4_addr[IPV4_ALEN]; unsigned char mac_addr[ETH_ALEN]; /* used by mactelnetd */ int socketfd; #ifdef __linux__ int ifindex; #endif int has_mac; int in_use; }; extern int net_get_interfaces(struct net_interface *interfaces, int max_devices); extern struct net_interface *net_get_interface_ptr(struct net_interface *interfaces, int max_devices, char *name, int create); extern int net_init_raw_socket(); extern int net_send_udp(const int socket, struct net_interface *interface, const unsigned char *sourcemac, const unsigned char *destmac, const struct in_addr *sourceip, const int sourceport, const struct in_addr *destip, const int destport, const unsigned char *data, const int datalen); extern unsigned short in_cksum(unsigned short *addr, int len); #endif mactelnet-0.4.0/Changelog0000644000000000000000000006743312001351671014010 0ustar rootrootcommit b3e038acf0a8303b943ebd06e2d067a0761a6edd Author: Håkon Nessjøen Date: Tue Jul 17 22:25:21 2012 +0200 New version 0.4.0. commit 8bb7351cc1598da5ef6b799c019c75509a9a642f Author: Håkon Nessjøen Date: Tue Jul 17 22:20:59 2012 +0200 Updated internationalization, sped up code by using fputs instead of fprintf. Updated readme. Bumped version. commit 092e396b00ee4805c2a924f1b1c00cbc6e07a33c Author: Håkon Nessjøen Date: Tue Jul 17 22:19:19 2012 +0200 Added -U flag for dropping privileges in raw mode in mactelnet. Manually merged from Ali Onur Uyar's commit 8720817a0b in his MAC-Telnet repo at github (aouyar) commit 8d0a3a56e5ce113a962ff04255dc38abac08640f Author: Håkon Nessjøen Date: Sun May 20 17:20:00 2012 +0200 Fixed missing translation in i18n template. Bugfixed Makefile a bit. commit 7175eb2a1d83ae10a7bc0c1961a6d13fb40a1456 Author: Håkon Nessjøen Date: Sun May 20 16:53:56 2012 +0200 Added -l option to mactelnet, so you don't have to know about the mndp tool to find it. commit 2d1bb7ebafb3cfe9161854d1ac0b05133fa05139 Author: Håkon Nessjøen Date: Tue Feb 28 15:26:34 2012 +0100 Add comment about \r\n in i18n commit 0918879970d8b399512a9a4553d7989f2434c9a7 Author: Håkon Nessjøen Date: Tue Feb 28 14:39:42 2012 +0100 Update po template commit 86990fe50070268508caf171c825217c7da21ef5 Author: Håkon Nessjøen Date: Tue Feb 28 14:37:13 2012 +0100 Cleaned up i18n commit 210b1b5574afb381b87d6d34860009a905ed6848 Author: Håkon Nessjøen Date: Tue Feb 28 14:32:53 2012 +0100 Added i18n support commit 11ee3dc65c67d6a5c98347287cee50963029d412 Author: Håkon Nessjøen Date: Sat Feb 11 13:48:11 2012 +0100 Bugfix. Don't die on interfaces without address. commit 1ac6a78d69634e5c54bb8b6182995d1d84a9cf71 Author: Håkon Nessjøen Date: Mon Nov 21 19:17:22 2011 +0100 Fix Makefile to include LDFLAGS and LIBS commit 6a9192d4d4f1d5c6849de158a707f4cc759c3ea5 Author: Håkon Nessjøen Date: Mon Nov 21 18:20:53 2011 +0100 Removed librt as mandatory library. Only needed for kfreebsd. commit a5b710a45671c1b9504130d83d3ebe7fe8a65c5a Author: Håkon Nessjøen Date: Sun Nov 13 09:54:22 2011 +0100 Added support for reloading list of interfaces/addresses on HUP signal, and fixed notification to connections of TERM signal. commit 4d3923c1cc947fbf1a6b23e2adf6915c47aac8d1 Author: Håkon Nessjøen Date: Sun Nov 13 08:19:06 2011 +0100 Fix bug in interface enumerator commit e78481d2e5a4a3ea133980403041579b048ede74 Author: Håkon Nessjøen Date: Sun Nov 13 06:45:39 2011 +0100 Code "speedup". commit 62fbf67c2a27b10e6ff534c7795a96e38d259e55 Author: Håkon Nessjøen Date: Sun Nov 13 06:40:22 2011 +0100 Added comment to remind myself not from writing "non-root" version of macping any more times commit 3084b5ec02f72c7c420a5c6687a61df637005ceb Author: Håkon Nessjøen Date: Sun Nov 13 06:03:15 2011 +0100 Simplified checking of mac address (code cleanup) commit 632bc61784657ca10da047c38596bde9d336998f Author: Håkon Nessjøen Date: Sat Nov 12 05:15:36 2011 +0100 New version. 0.3.3. Moved versioning into config.h commit 94ac14d2765051a8992c3a822547bc09260492df Author: Håkon Nessjøen Date: Sat Nov 12 04:53:12 2011 +0100 Rewrote the interface handling. Added full support for kFreeBSD, have not tested with FreeBSD. commit 904d05c3d9dec35bad0413f933ea690868a09f4f Author: Håkon Nessjøen Date: Tue Nov 8 23:40:06 2011 +0100 Cleanup commit d876aad77b29f410c9c4218636482cab59504fac Author: Håkon Nessjøen Date: Tue Nov 8 23:06:39 2011 +0100 Clean up and bugfix endianess handling commit b7543bdfda84c0287dd0d183fa764c9931a4c211 Merge: 75ff364... 754ed32... Author: Håkon Nessjøen Date: Thu Nov 3 12:24:21 2011 -0700 Merge pull request #3 from bbonev/master misc fixes from Boian Bonev commit 754ed32a9979fd34ee5ceaab451ddd5810faabc6 Author: Boian Bonev Date: Fri Nov 4 00:30:41 2011 +0530 move trypassword inside the connection state; generate enckey only once per session commit a987cb67dcda1986b66434244afca24b50bff15d Author: Boian Bonev Date: Thu Nov 3 23:16:20 2011 +0530 handle signals in foreground mode as well commit ab1d9657ca42ab7576473bcd6726ba5e8ab2fcbe Author: Boian Bonev Date: Thu Nov 3 21:48:35 2011 +0530 tell the new shell that its a login one commit 75ff364cd556c1ad8cfe742f0d58d5751807c111 Author: Håkon Nessjøen Date: Wed Nov 2 20:42:17 2011 +0100 Buffer overflow prevention. commit 2df57f592c0760b15707e87537e29aebaa83ee87 Author: Håkon Nessjøen Date: Wed Nov 2 19:28:05 2011 +0100 Quiet mode and no terminal setup when not talking to a tty commit 0df0f028bb355547ac50ea5756edb14e3d12f562 Merge: 18139b6... a60f40d... Author: Håkon Nessjøen Date: Mon Oct 31 01:43:34 2011 -0700 Merge pull request #2 from bbonev/master fix uptime byte order, by bbonev commit a60f40dd38f7f2d3b621bff914589c5be7803165 Author: Boian Bonev Date: Fri Oct 28 10:18:00 2011 +0530 use unified byte order conversion for uptime commit 18139b6417e6d09a9c8ddf3291179d77c19bde5e Author: Håkon Nessjøen Date: Thu Aug 11 00:46:42 2011 +0200 New minior version commit 053b2fdf6400a2557bd1a4340f2fbeefedfcff13 Author: Håkon Nessjøen Date: Thu Aug 11 00:30:29 2011 +0200 Cleanup in Makefile and docs according to tips from Nelson A. de Oliveira commit 7852da33d25ced23652089f1942ff38e52693ebc Author: Håkon Nessjøen Date: Wed Aug 10 23:57:04 2011 +0200 Remove unused variables. Thanks to "Nelson A. de Oliveira" commit de36588baa006bd6f5b2a2ce35914dba8ee53d5a Author: Håkon Nessjøen Date: Sun May 1 22:26:22 2011 +0200 Add important information to manual pages commit a4cc2b5e1ab748241f8a86bb4cd09043abc02a02 Author: Håkon Nessjøen Date: Sun May 1 16:25:27 2011 +0200 Cleaned up description and synopsis of files commit 133b70c2dc57213d8c3891b0d6c925f73419b555 Author: Håkon Nessjøen Date: Sun May 1 14:30:36 2011 +0200 Added manual pages and added license text to all .h and .c files. commit 96eaa3fff04027dc8760b570ec64592bec1777fd Author: Håkon Nessjøen Date: Sun Feb 27 16:11:51 2011 +0100 New minior version commit d4141ba5a1ca0a3374cbd2e0ff55b3c63719ec28 Author: Håkon Nessjøen Date: Sun Feb 27 16:08:26 2011 +0100 Removed .deb specific files and updated makefile/readme commit 9f9610327c6b5dd3f738b6dddcc77646376d9fd9 Author: Håkon Nessjøen Date: Sun Feb 27 15:09:56 2011 +0100 Add foreground mode support for mactelnetd. commit 5b786ccb2a21937fcc6e1a29167db47f1d78abb5 Author: Håkon Nessjøen Date: Sun Feb 27 14:27:29 2011 +0100 Code cleanup. commit e149992b6487bb41308a1893500e35bbe6d195c0 Author: Håkon Nessjøen Date: Sun Feb 27 13:38:03 2011 +0100 Missing two endianness checks/handling. Tested successfully with MIPS Malta 4Kc qemu emulator (big endianed) commit abd75d40f31787f289de8e34854c00672af49b2c Author: Håkon Nessjøen Date: Thu Feb 24 21:13:57 2011 +0100 Fixed textual typo commit 5eb1c8e5c125902e803c3ff99ca88438223a6495 Author: Håkon Nessjøen Date: Thu Feb 24 17:05:02 2011 +0100 Enhance send_udp routine to actually check the incoming packet for ACK commit cb6fe86292fd85a67dfd930cdc351fec0ddf96bc Author: Håkon Nessjøen Date: Thu Feb 24 16:46:30 2011 +0100 Code cleanup commit f77147c698364fb38c226895556176abd61d3217 Author: Håkon Nessjøen Date: Thu Feb 24 04:48:17 2011 +0100 Fixed permissions of slave pts, so the connecting user has access to his own pts. Now applications like screen also works. commit 51073f378c05590539dabdbe61034ab548078e6e Author: Håkon Nessjøen Date: Thu Feb 24 03:13:26 2011 +0100 Have faith in htons/ntohs functions being transparent on big endianed build environments. commit d5f936e9c017f884b070f41748ce502a0bb131d7 Author: Håkon Nessjøen Date: Thu Feb 24 03:06:39 2011 +0100 Bugfix of two bugs making raw mode unusable/unstable. commit a2b0eda2d0ac5910ade5fa1193dae0c56a521ecb Author: Håkon Nessjøen Date: Wed Feb 23 12:29:41 2011 +0100 Added "fast mode" to macping. Also fixed the way the summary was printed out, to imitate standard ping utility. commit 0e0ff418da0d95f9e7b8a25d7643dd4c5e8731d8 Author: Håkon Nessjøen Date: Wed Feb 23 12:11:29 2011 +0100 Added endianness checks in udp.c, for raw packets commit 59cdd34a3248acac61fd3edebca860066fd4c2fd Author: Håkon Nessjøen Date: Wed Feb 23 11:59:02 2011 +0100 Bugfix in mactelnet. Raw mode did not successfully autodetect outgoing interface. commit d009537a6eceda1bdc5abddb50f41f2030d0dacc Author: Håkon Nessjøen Date: Mon Feb 21 18:05:49 2011 +0100 Fixed up Makefile a bit commit c499742b5d3065da5f232cab9efb060eb67e1a23 Author: Håkon Nessjøen Date: Mon Feb 21 17:31:04 2011 +0100 Busted :P commit 0589a8fc2e521ac30167eb51d4a373477e98c525 Author: Håkon Nessjøen Date: Mon Feb 21 17:26:08 2011 +0100 Removed invalid text in help screen of mactelnet commit 28ce685f858511f7fa65c06e091e7d473dc2cc94 Author: Håkon Nessjøen Date: Mon Feb 21 17:20:13 2011 +0100 Add endianness checking/conversion. commit 0058ac3010d79bf086ddfa0be9a44ee419bf7058 Author: Håkon Nessjøen Date: Mon Feb 21 15:53:35 2011 +0100 Added MT_PTYPE_PING/PONG support in mactelnetd and added a macping tool. For this udp-checksum code was also added for raw packets. commit d3f4e55538788ec7569c5eb4a21622c516aa0d92 Author: Håkon Nessjøen Date: Wed Feb 16 19:39:11 2011 +0100 Fix: Send IP address (if available) of machine also when sending mndp packets using raw udp mode commit 09d8ca45a5f0711ae28988ccfbaf917439c31b44 Author: Håkon Nessjøen Date: Wed Feb 16 19:13:27 2011 +0100 Rewrote MNDP parser, and added MNDP broadcast routines for mactelnetd. Thanks to "Marcin Ulikowski" for MNDP reverse engineering. mactelnetd will now be recognized by other routeros devices/applications as neighbours. commit ec7d3b484b317195f6facf79d469bb9c8939a2e5 Author: Håkon Nessjøen Date: Wed Feb 16 04:05:27 2011 +0100 Forgot to remove some debugging commit ac5b0eadef805d968bb922e0cf1b635da3e80972 Author: Håkon Nessjøen Date: Wed Feb 16 03:54:49 2011 +0100 mactelnetd only listened on interfaces with an ip on it. Rewrote mactelnetd to use all IFs it finds MAC addresses on, not only the ones with IP. Testing version, to be cleaned up. commit 82fd4b116dd061b72dd88800a45b4cd302191b57 Author: Håkon Nessjøen Date: Mon Dec 27 00:22:38 2010 +0100 Added support for broadcast packets in mactelnetd also. Fixed a bug where the device index was hardcoded in send_custom_udp(). Renamed "broadcast_mode" to "use_raw_socket". commit e28d1808ff78900205bfd6e52964a695e5048118 Author: Håkon Nessjøen Date: Sun Dec 26 23:17:58 2010 +0100 Improved the keepalive-timer in mactelnet, and fixed a terminal reset bug if your connection timed out. commit 7e31888710ee50b99e569f8b64b0cdf80dd69a5d Author: Håkon Nessjøen Date: Sun Dec 26 20:12:57 2010 +0100 Added code to check if it should answer mactelnet packets or not in mactelnetd. commit 423615514bd1cd5e5a90b68ee25f9fbb030f7af1 Author: Håkon Nessjøen Date: Sun Dec 26 17:57:47 2010 +0100 Janitor work commit 98b82ee3a77ef4ffd79472e0fd56d6deced1d8e4 Author: Håkon Nessjøen Date: Sun Dec 26 15:28:37 2010 +0100 Code cleanup, and made timeout-acking more correct commit 425d09a5ddbb1aed1c6c11a11165719fa63d0a5e Author: Håkon Nessjøen Date: Sat Dec 25 23:48:03 2010 +0100 Official version 0.2 commit 52edeba4b440aa0cc84d458caa40fb40f8488a63 Author: Håkon Nessjøen Date: Sat Dec 25 23:20:32 2010 +0100 Add support for dash-seperated mac addresses commit 25476c74e2fe93163e50f41a0dc15b3088c6f65f Author: Håkon Nessjøen Date: Sat Dec 25 23:08:49 2010 +0100 Moved global protocol info to protocol header, where it belongs commit 8e2e73c7d861595f7e9a94eb4d7faf60addc0a2d Author: Håkon Nessjøen Date: Sat Dec 25 22:58:50 2010 +0100 Added simple DATA packet retransmission support. commit 93d82ea7dd279e9a0eba68d4de49dc87ffa5ad7c Author: Håkon Nessjøen Date: Sat Dec 25 19:18:22 2010 +0100 Change naming convention on variable names as well commit 2d9057c497585c4eb76e5f3ad4f623da56a2e28c Author: Håkon Nessjøen Date: Fri Dec 24 01:52:10 2010 +0100 Changed naming convention on function names commit dbadc1ab26b3cca6b3697d9c07f284f582dde75d Author: Håkon Nessjøen Date: Fri Dec 24 01:51:44 2010 +0100 Fixed a bug where the mndp port/socket was not closed after a parseMNDP call. commit c91ff9668142a9d0aac0bc364ccaf40611fa9c72 Author: Håkon Nessjøen Date: Thu Dec 23 15:54:40 2010 +0100 Cleaned up code and added -Wall to the compiler flags. Moved packet types over to enums for more ease of use. commit 20746581ba3e8c6cda0851e47b27528401168247 Author: Håkon Nessjøen Date: Thu Dec 23 12:42:58 2010 +0100 Added u/wtmp logout code, and did some minior code cleanup. commit fae8147bc4a3c646dfa852074266b23f8a242450 Author: Håkon Nessjøen Date: Thu Dec 23 03:33:51 2010 +0100 Show mac address of client in syslog, and save correct mac address for wtmp. commit ff590f394b61c88922ef5a5bb5349b81c6d0be55 Author: Håkon Nessjøen Date: Thu Dec 23 03:10:56 2010 +0100 Fix silly bug that made mactelnetd connections time out after only 65k bytes commit 53ef36ccf50163e72b646ef4bf673669f9c8de2e Author: Håkon Nessjøen Date: Thu Dec 23 01:33:14 2010 +0100 Added syslog logging. Added daemonizing of application. Cleaned up login code to correctly set up controlling terminal. commit 1cf099bd1a371ef3a307906c46ae128f6e2bf025 Author: Håkon Nessjøen Date: Tue Dec 21 00:56:19 2010 +0100 Added "nologin" support. And cleaned up a little duplicated code. commit fadddf392dd27b0fffd8b66c38f240bf0f8afd86 Author: Håkon Nessjøen Date: Mon Dec 20 23:54:20 2010 +0100 Fix silly warning about ether_ntoa argument commit bc9266f2ae0ebf80deb2817dded7a26d8c65686b Author: Håkon Nessjøen Date: Mon Dec 20 00:09:52 2010 +0100 Added wtmp/utmp support. Fixed setuid/setgid bug and error detection. Added motd message. Minior code cleanup. commit 1fb3f642b29c4e9af002dac9830bd98f7b25e145 Author: Håkon Nessjøen Date: Sun Dec 19 20:44:42 2010 +0100 Code cleanup in mactelnet daemon commit 59525a228a1ebf2aca46d5be63f8280b274a490a Author: Håkon Nessjøen Date: Sun Nov 28 23:31:13 2010 +0100 Added a little documentation in the source code commit 3f669049e77b87cca9168fbd55838bd679b573c4 Author: Håkon Nessjøen Date: Fri Nov 19 01:52:54 2010 +0100 Handle network devices without address information correctly. commit 749229fa367aed0bb14822a4e2fbbf112d06033e Author: Håkon Nessjøen Date: Wed Nov 3 03:12:11 2010 +0100 Skip loopback interfaces. They seldom/never have a MAC address, and you probably won't run a MAC-Telnet server there. Speeds up autodetect. commit 1c11ee970aaa1dde00028508517e2f8964cd54ea Author: Håkon Nessjøen Date: Wed Nov 3 03:04:41 2010 +0100 Added missing file, documentation fixup, and minifixup in makefile commit 3103d2c9c237101abf143dd19e9998a426c0d9ec Author: Håkon Nessjøen Date: Wed Nov 3 02:49:33 2010 +0100 Started code for auto-detecting interface. Working proof of concept version. Raw socket version not updated yet. commit 40362c46806d033316e859db772f46c5652fbea3 Author: Håkon Nessjøen Date: Tue Nov 2 18:09:32 2010 +0100 Simplified the way parseControlPacket is looped/called commit a993f53f4ab8e08bfa2c198d9375f85686e87c9f Author: Håkon Nessjøen Date: Mon Nov 1 23:41:49 2010 +0100 Minior fix: Move mac-address code downwards according to the order of arguments. So problems with the ifname will be reported before problems with the mac address/identity name. commit 50d04396d84bcf0adf1b44223c4d751562639225 Author: Håkon Nessjøen Date: Mon Nov 1 23:06:26 2010 +0100 Removed dependency of libssl/crypto. Added L. Peter Deutsch's implementation of MD5 instead. commit f241a46d9901f6c6c679838b35c90cc3619167be Author: Håkon Nessjøen Date: Mon Nov 1 22:46:34 2010 +0100 Added support for connecting to your router via the router identity name. (using MNDP) commit 1b94292a0fb5cfeb42aaf0039e7865a07aa1ef3f Author: Håkon Nessjøen Date: Mon Oct 18 16:44:33 2010 +0200 A lot of small fixes to mactelnetd commit 94113dbaec206b4c15b5b03871ae3642efaf0290 Author: Håkon Nessjøen Date: Mon Oct 11 01:16:10 2010 +0200 Renamed files, added license info and did some minior fixes. commit 8a9a47179332700c5c270dafc6ef014417015f99 Author: Håkon Nessjøen Date: Mon Oct 11 00:02:11 2010 +0200 First version of mac-telnet server daemon mactelnetd. Use with care until it has been tested enough. Not for production use. To be cleaned up a lot. commit 7b0347285ecb0b78ce0b699a1a6c9e50e22f7f07 Author: Håkon Nessjøen Date: Tue Oct 5 00:07:20 2010 +0200 Added files for packaging mactelnet for debian/ubuntu commit 5bd380b35e7b8f6acca24635f393d216e92cb2b5 Author: Håkon Nessjøen Date: Mon Oct 4 21:56:03 2010 +0200 Updated readme to reflect recent changes. commit 4f2f6ad13a03cc253069cb63224112f7a3a82fbb Author: Håkon Nessjøen Date: Mon Oct 4 21:46:37 2010 +0200 * Added support for using broadcast messages, instead of using raw socket to send data. * Started using getopts to handle command line arguments. * Cleaned up some debug stuff. commit d22fb7e1c12eaeeef90af97386fe3c5c84a0a9eb Author: Håkon Nessjøen Date: Mon Oct 4 16:06:52 2010 +0200 Security fixes, etc. strn* functions does not terminate strings if they exceed the length parameter. commit 4c8978d341731e5aa49bc877214d145bfde0bc20 Author: Håkon Nessjøen Date: Mon Oct 4 11:38:00 2010 +0200 Minior code cleanup commit 3e4740e94d5151783085b16df6d76692cfa9cb5f Author: Omni Flux Date: Mon Oct 4 03:10:24 2010 -0600 Send query MNDP packet before listening for MNDP packets commit 0130c93407610720cb1b0c654a2dd79f9a4f165d Author: Håkon Nessjøen Date: Sun Oct 3 03:47:16 2010 +0200 Code cleanup commit 5025b70fae9ab2d79deac9e08d806a85c339ddbe Author: Håkon Nessjøen Date: Sun Oct 3 03:46:35 2010 +0200 Fix invalid counter sizes which would break connection after 65535 bytes of data in one direction commit fb6540513cdb72f874cdb409e493171c94e59460 Author: Håkon Nessjøen Date: Sun Oct 3 03:15:23 2010 +0200 Documentation changes commit 065bb72362c52603bd615b0a69e24a6f00f03932 Author: Håkon Nessjøen Date: Sun Oct 3 02:44:37 2010 +0200 Changed how packet generation functions get access to the buffer, so they won't let you overflow the buffer, and they will keep track of the packet size "internally". commit a64b7069f5144dbd2e76f3a9d104d63ca64c7cd1 Author: Håkon Nessjøen Date: Sat Oct 2 20:33:45 2010 +0200 Commented the rest of main() commit 2643ff20775e36ddd37c806fc7f943c2c0919f2b Author: Håkon Nessjøen Date: Sat Oct 2 20:28:15 2010 +0200 Cleanup and comment main.c commit 39c77a5676f77061ba0a8a116f29e35664808a60 Author: Håkon Nessjøen Date: Sat Oct 2 19:49:37 2010 +0200 Rewrote auth code. Also removed bug where password had to be 8 characters long. And where md5sum could not have a character of value 0 in it. commit 1d6edd6cb66c65d9b5b13637465a901d17a23b10 Author: Håkon Nessjøen Date: Sat Oct 2 16:48:11 2010 +0200 Add some missing data to the internal protocol headers commit b451464a088999137097e7b364942bac12a65e67 Author: Håkon Nessjøen Date: Sat Oct 2 16:38:26 2010 +0200 Drop double/old packets. No more random buggy terminal! commit 5d3806897b1d9b406135ba9b8b460ed5b5a21cf0 Author: Håkon Nessjøen Date: Sat Oct 2 11:48:42 2010 +0200 Updated README commit 01982930a4852345c3b54d2c82f5c5ae7a2d970f Author: Håkon Nessjøen Date: Sat Oct 2 11:19:52 2010 +0200 Send more than 1 byte at the time if more exists in the buffer commit b898569df5c7388500d76d9b96f9111ba09c2ff3 Author: Håkon Nessjøen Date: Fri Oct 1 12:24:39 2010 +0200 Made the password parameter optional; You may now write your password in a prompt instead of polluting your history with passwords. commit 79153f655b1f8af1df6b36875c2d0b61386b33a9 Author: Håkon Nessjøen Date: Fri Oct 1 11:34:25 2010 +0200 Added install option to Makefile, and fixed a "typo" commit d50a913b21b1ceec3bf22915caa87a8a9b44e3d1 Author: Håkon Nessjøen Date: Fri Oct 1 11:09:27 2010 +0200 Added keepalive functionality commit c9711c2fa0ae0efbf0e847d4226d0ab04edc05f2 Author: Håkon Nessjøen Date: Fri Oct 1 10:31:28 2010 +0200 Some code cleanup, and support for several sessions/instances on one interface. (random source port) commit 471b10f6b547bb9b6088c8b079360ad91aaf8510 Author: Håkon Nessjøen Date: Fri Oct 1 09:34:16 2010 +0200 Header-cleanup and get terminal type from ENV commit 2c20599c89f256e656b089907742d2297d7a317c Author: Håkon Nessjøen Date: Fri Oct 1 09:27:48 2010 +0200 Added resize handler commit 046c16b0778d6b4112a32b61c274871dc6a0b43b Author: Håkon Nessjøen Date: Fri Oct 1 00:44:09 2010 +0200 Milestone 1: First fully functional (proof of concept) version. commit c56e309956da3d41420db1c5d41ccf245c594e45 Author: Håkon Nessjøen Date: Thu Sep 30 11:42:19 2010 +0200 Add a lot of comments to the code commit 87341fcc53b58d270528192607d3ce547abffa77 Author: Håkon Nessjøen Date: Thu Sep 30 00:13:13 2010 +0200 Added a simple tool for listing local mikrotik routers by mac address commit c90ce96f3f86404ee85b390a3ed4b575a257423d Author: Håkon Nessjøen Date: Tue Sep 28 00:07:49 2010 +0200 Comment cleanup commit 86460e9be93df399286e63b8142853d6e5aee5a9 Author: Håkon Nessjøen Date: Mon Sep 27 16:46:07 2010 +0200 Minifixes commit ee5e037df930a4a877cd5de865dd884b3d83814f Author: Håkon Nessjøen Date: Mon Sep 27 15:37:18 2010 +0200 No need to re-invent a square version of the wheel... cleanup commit 3afa38b2e38a53441ce55bf5932553a8672268bf Author: Håkon Nessjøen Date: Mon Sep 27 15:26:47 2010 +0200 Cleaned up src/dst mac/ip handling a bit. Now fully automates source ip/mac addresses according to ethernet device chosen. commit ccda1f219d6a07b59d2ebf69f7c0864aba397098 Author: Håkon Nessjøen Date: Mon Sep 27 13:30:31 2010 +0200 Forgot to free memory commit f68b4c26f99cad5efb608fab92ccb7d2a54ca7a8 Author: Håkon Nessjøen Date: Mon Sep 27 13:28:19 2010 +0200 Started code for automatically defining src ip/mac for packets commit dcf815703b327bd6500c0bdea60cb85f67994d5a Author: Håkon Nessjøen Date: Sun Sep 26 22:13:47 2010 +0200 Cleanup, and correctly handle connection closing commit db4ec3f49051dbd35e2274a0cd1c93193d4511ae Author: Håkon Nessjøen Date: Sun Sep 26 21:28:30 2010 +0200 Command line control of mac, user and pass... main() should be rewritten, and should autodetect src mac/ip address, or let you specify commit 52ac09faa8fdd5d25b02f310ca6b2c497b45806d Author: Håkon Nessjøen Date: Sun Sep 26 20:51:39 2010 +0200 GPL'd it commit 0543208957f3f1a14f66d0c70fcc813e779f7638 Author: root Date: Sun Sep 26 20:32:34 2010 +0200 Working login, buggy terminal-data reception commit d0b22a46b53c968de3ec85022251f318d97e6b27 Author: root Date: Sun Sep 26 10:38:19 2010 +0200 Files splitted commit f7cfcdb6b1fcfaf149dce2195181f3d8707306b6 Author: root Date: Sun Sep 26 02:00:11 2010 +0200 Connection working, auth received, control packets parsed. TODO: Cleanup/filesplit and create login + terminal code. commit 10a51f687aab0673ff6be875b3b3e0dfe304e2b2 Author: root Date: Sat Sep 25 21:03:28 2010 +0200 Last version commit 6ad8dc8a9585fbd3f5ea45d70878edaa713c6af5 Author: root Date: Sat Sep 25 18:12:53 2010 +0200 Done splitting files commit 61809b4cf7467ae3988a2f6832c94d4d211552c8 Author: root Date: Sat Sep 25 18:09:38 2010 +0200 Done splitting files commit 7d9e514c276648b1db2286e780649f08c17225ca Author: root Date: Sat Sep 25 18:03:41 2010 +0200 cleanup2 commit cebde44c31c50939ea690718a83a55eb5016fb2a Author: root Date: Sat Sep 25 17:59:53 2010 +0200 cleanup commit 3148553efa081253644f6c20724dfbddb487d7f7 Author: root Date: Sat Sep 25 17:56:20 2010 +0200 rename commit efab1538ab2a7c39aae29a8d3870d00059fc52a0 Author: root Date: Sat Sep 25 17:55:20 2010 +0200 First working version: main2.c commit 0aeab827e8011cdd71e29865574567325f830a4e Author: root Date: Sat Sep 25 12:35:50 2010 +0200 First import mactelnet-0.4.0/console.c0000664000000000000000000000415012001345061013765 0ustar rootroot/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include struct termios orig_term; int raw_term() { struct termios new; if (tcgetattr(STDIN_FILENO, &orig_term) < 0) { perror("tcgetattr"); return -1; } memcpy(&new, &orig_term, sizeof(struct termios) ); /* raw mode, from tcsetattr man page */ new.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); new.c_cflag &= ~(CSIZE|PARENB); new.c_cflag |= CS8; if (tcsetattr(STDIN_FILENO, TCSANOW, &new) < 0) { perror("tcsetattr"); return -1; } return 0; } int reset_term() { if (tcsetattr(STDIN_FILENO, TCSANOW, &orig_term) < 0) { perror("tcsetattr"); return -1; } return 0; } int get_terminal_size(unsigned short *width, unsigned short *height) { struct winsize ws; if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) { perror("TIOCGWINSZ"); return -1; } *width = ws.ws_col; *height = ws.ws_row; return 0; } int set_terminal_size(int fd, unsigned short width, unsigned short height) { struct winsize ws; ws.ws_col = width; ws.ws_row = height; if (ioctl(fd, TIOCSWINSZ, &ws) != 0) { perror("TIOCSWINSZ"); return -1; } return 0; }