├── .gitignore ├── configure.ac ├── autogen.sh ├── Makefile ├── Makefile.in ├── config.h ├── README.md ├── LICENSE └── ipxgw.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /ipxgw 2 | *.o 3 | config.log 4 | config.status 5 | configure 6 | autom4te.cache/ 7 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([ipxgw], [1.0]) 2 | # AM_INIT_AUTOMAKE 3 | AC_PROG_CC 4 | AC_CONFIG_FILES([Makefile:Makefile.in]) 5 | AC_OUTPUT -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #This is to be run from the project's own autogen.sh in the project folder. 2 | git update-index --assume-unchanged Makefile 3 | aclocal || die "aclocal failed" # Set up an m4 environment 4 | autoconf || die "autoconf failed" # Generate configure from configure.ac 5 | echo Configure script is generated. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq (,$(INSTALL)) 2 | INSTALL = install 3 | endif 4 | 5 | ifeq ($(DESTDIR)$(bindir),) 6 | bindir = /bin 7 | endif 8 | 9 | bindir := $(DESTDIR)$(bindir) 10 | 11 | all: ipxgw 12 | 13 | ipxgw: ipxgw.o 14 | g++ -Wall ipxgw.o `pkg-config --libs SDL_net` -lpcap -o ipxgw 15 | 16 | ipxgw.o: ipxgw.cpp config.h 17 | g++ -Wall `pkg-config --cflags SDL_net` -c ipxgw.cpp 18 | 19 | clean: 20 | rm -fv *.o ipxgw 21 | 22 | install: ipxgw 23 | $(info Installing...) 24 | #Requiring user rights for pcap 25 | #Make sure that the group exists 26 | @groupadd -f pcap 27 | ifneq (,$(PCAPUSER)) 28 | usermod -a -G pcap $(PCAPUSER) 29 | endif 30 | $(INSTALL) -m 0755 ipxgw $(bindir) 31 | $(info Adding pcap rights...) 32 | #Set the pcap rights to the app! 33 | @chgrp pcap $(bindir)/ipxgw 34 | @setcap cap_net_raw,cap_net_admin=eip $(bindir)/ipxgw -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile to build and install the SDL library 2 | 3 | top_builddir = . 4 | srcdir = @srcdir@ 5 | objects = build 6 | gen = gen 7 | prefix = @prefix@ 8 | exec_prefix = @exec_prefix@ 9 | bindir = @bindir@ 10 | libdir = @libdir@ 11 | includedir = @includedir@ 12 | datarootdir = @datarootdir@ 13 | datadir = @datadir@ 14 | auxdir = @datarootdir@/aux 15 | distpath = $(srcdir)/.. 16 | distdir = $(BUILD_NAME)-@SDL_VERSION@ 17 | distfile = $(distdir).tar.gz 18 | 19 | #@SET_MAKE@ 20 | SHELL = @SHELL@ 21 | CC = @CC@ 22 | INCLUDE = -I$(includedir) 23 | CFLAGS = 24 | EXTRA_CFLAGS = 25 | LDFLAGS = 26 | EXTRA_LDFLAGS = 27 | LIBTOOL = libtool 28 | INSTALL = install 29 | AR = ar 30 | RANLIB = ranlib 31 | WINDRES = windres 32 | 33 | all: ipxgw 34 | 35 | ipxgw: ipxgw.o 36 | g++ -Wall ipxgw.o `pkg-config --libs SDL_net` -lpcap -o ipxgw 37 | 38 | ipxgw.o: ipxgw.cpp config.h 39 | g++ -Wall `pkg-config --cflags SDL_net` -c ipxgw.cpp 40 | 41 | clean: 42 | rm -fv *.o ipxgw 43 | 44 | install: ipxgw 45 | $(info Installing...) 46 | #Requiring user rights for pcap 47 | #Make sure that the group exists 48 | @groupadd -f pcap 49 | ifneq (,$(PCAPUSER)) 50 | usermod -a -G pcap $(PCAPUSER) 51 | endif 52 | $(INSTALL) -m 0755 ipxgw $(bindir) 53 | $(info Adding pcap rights...) 54 | #Set the pcap rights to the app! 55 | @chgrp pcap $(bindir)/ipxgw 56 | @setcap cap_net_raw,cap_net_admin=eip $(bindir)/ipxgw -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2010 The DOSBox Team 3 | * Copyright (C) 2020 Joel Lehtonen 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #include 21 | 22 | // This feature should be tested but assuming recent enough gcc 23 | #define GCC_ATTRIBUTE(x) __attribute__ ((x)) 24 | 25 | typedef double Real64; 26 | 27 | typedef uint8_t Bit8u; 28 | typedef int8_t Bit8s; 29 | 30 | typedef uint16_t Bit16u; 31 | typedef int16_t Bit16s; 32 | 33 | typedef uint32_t Bit32u; 34 | typedef int32_t Bit32s; 35 | 36 | typedef uint64_t Bit64u; 37 | typedef int64_t Bit64s; 38 | 39 | typedef uint_least32_t Bitu; 40 | typedef int_least32_t Bits; 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DOSBox IPXNET to real IPX network gateway 2 | 3 | This is a small program which contains parts from DOSBox sources which 4 | enables it to act as a IPXNET server where DOSBox(es) can connect to. 5 | Besides being a dedicated server it also mirrors the IPX packets between 6 | a real physical ethernet network where real DOS computers can be 7 | connected to. This allows playing IPX games between real computers on 8 | one end and DOSBox emulators at another end. 9 | 10 | ## Compiling 11 | 12 | Ipxgw requires libpcap, SDL 1.2, and SDL_net libraries with headers 13 | installed besides g++ and standard C headers to compile. If you are 14 | running Debian or Ubuntu, install requirements by running: 15 | 16 | sudo apt install build-essential libpcap-dev libsdl-net1.2-dev 17 | 18 | Then just: 19 | 20 | make 21 | 22 | There is also autotools support added. 23 | 24 | ## Usage 25 | 26 | If you are running "modern" IPX network at your LAN, then you just 27 | need to define the interface where your IPX network is. In case the 28 | interface is `eth0`, run: 29 | 30 | ipxgw eth0 31 | 32 | Because low level packet capture is required, superuser privileges are 33 | normally needed. Use `sudo` if needed. 34 | 35 | UDP port 213 is used by default and can be changed using `-p` option. 36 | 37 | If your computers in real network are running Novell raw IEEE 802.3 38 | IPX stack instead of Logical Link Control (IEEE 802.2), then you need 39 | to change the frame structure with Ipxgw `-r` switch. For example: 40 | 41 | ipxgw -r eth0 42 | 43 | If your computers in real network are running Ethernet II 44 | IPX stack instead of IEEE 802.x, then you need 45 | to change the frame structure with Ipxgw `-e` switch. For example: 46 | 47 | ipxgw -e eth0 48 | 49 | Ethernet II also adds dynamic IPX node number allocation on the host 50 | network, to prevent conflicting IPX node numbers. 51 | 52 | More information at [Wikipedia](https://en.wikipedia.org/wiki/Ethernet_frame#Novell_raw_IEEE_802.3). 53 | 54 | To see other available parameters, use -h for help. 55 | 56 | ## DOSBox configuration 57 | 58 | More comprehensively documented in 59 | [DOSBox Wiki](https://www.dosbox.com/wiki/Connectivity#IPX_emulation). 60 | This is a short summary: 61 | 62 | First, enable IPX. Ensure you have the following in DOSBox 63 | configuration: 64 | 65 | ```ini 66 | [ipx] 67 | ipx=true 68 | ``` 69 | 70 | Then run the following on DOSBox where *10.0.0.1* and *213* are the IP 71 | address of the machine running Ipxgw and Ipxgw port number: 72 | 73 | ```bat 74 | IPXNET CONNECT 10.0.0.1 213 75 | ``` 76 | 77 | ## Background 78 | 79 | We were lazy and so config.h has some hard-coded values. They should 80 | suffice for most users and the code compiles and works at least with 81 | both AMD64 Linux system and 32-bit Raspberry Pi. 82 | 83 | This is untested with combination of multiple real DOS computers, but it 84 | works with at least one. Problem might also be if you use a switch and not 85 | a simple old hub with those multiple computers because some packets might 86 | not be visible to the gateway and therefore not sent to DOSBox(es). 87 | 88 | You might ask, why do this? Well, there exists NE2000 driver for DOSBox 89 | but that does not work over the Internet - it allows only a local DOS 90 | computer to talk with a local DOSBox. This is the only way to allow 91 | remote DOSBox people to connect with your real DOS computer to play IPX 92 | games, as long as you can run the server. 93 | 94 | The code could be improved a lot as it was just quickly hacked together 95 | and then made to work with help of some wireshark debugging. Feel free 96 | to improve it as the license allows. 97 | 98 | ## License 99 | 100 | Copyright (C) 2015, 2023 Kati Salin 101 | Copyright (C) 2020 Joel Lehtonen 102 | 103 | Licenced under the terms of the GNU General Public License as 104 | published by the Free Software Foundation; either version 2 of the 105 | License, or (at your option) any later version. 106 | 107 | Contains parts from DOSBox source code by The DOSBox Team, under GPLv2 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /ipxgw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * DOSBox IPXNET to real IPX network gateway 3 | * Copyright (C) 2015 Jussi Salin 4 | * Contains parts from DOSBox source code by The DOSBox Team, under GPLv2 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | //Adjustments for Ethernet and UniPCemu-compatible allocation by Superfury 22 | 23 | #include 24 | #include 25 | #include 26 | #include "config.h" 27 | #include 28 | #include 29 | #include "SDL_net.h" 30 | #include 31 | #include 32 | #include //Timekeeping! 33 | 34 | #define ETHER_ADDR_LEN 6 // Ethernet addresses are 6 bytes, for use with pcap 35 | #define ETHER_HEADER_LEN 14 // Ethernet header is two addresses and two bytes size, for use with pcap 36 | #define ENCAPSULE_LEN 3 // Header for encapsulating IPX to Ethernet, for use with pcap 37 | #define SOCKETTABLESIZE 16 // From DosBox 38 | #define CONVIP(hostvar) hostvar & 0xff, (hostvar >> 8) & 0xff, (hostvar >> 16) & 0xff, (hostvar >> 24) & 0xff // From DosBox 39 | #define CONVIPX(hostvar) hostvar[0], hostvar[1], hostvar[2], hostvar[3], hostvar[4], hostvar[5] // From DosBox 40 | #define IPXBUFFERSIZE 1424 // From DosBox 41 | #undef DEBUG // More output if defined 42 | //Define below if you want to debug the network number functionality. 43 | //#define DEBUGNW 44 | 45 | //Timeout until a IPX node number is decided to be usable. Replies to the echo reset the timer until none reply within the timeout after the request. 46 | #define ALLOCATE_IPXNODE_ECHO_TIMEOUT 500000 47 | 48 | /*! 49 | * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's 50 | * a file descriptor, and therefore a signed integer. 51 | * We define SOCKET to be a signed integer on UN*X, so that it can 52 | * be used on both platforms. (from pcap/socket.h) 53 | */ 54 | #ifndef SOCKET 55 | #define SOCKET int 56 | #endif 57 | 58 | // From DosBox 59 | typedef Bit32u RealPt; 60 | 61 | // From DosBox 62 | struct PackedIP { 63 | Uint32 host; 64 | Uint16 port; 65 | } GCC_ATTRIBUTE(packed); 66 | 67 | // From DosBox 68 | struct nodeType { 69 | Uint8 node[6]; 70 | } GCC_ATTRIBUTE(packed) ; 71 | 72 | // From DosBox 73 | struct IPXHeader { 74 | Uint8 checkSum[2]; 75 | Uint8 length[2]; 76 | Uint8 transControl; // Transport control 77 | Uint8 pType; // Packet type 78 | 79 | struct transport { 80 | Uint8 network[4]; 81 | union addrtype { 82 | nodeType byNode; 83 | PackedIP byIP ; 84 | } GCC_ATTRIBUTE(packed) addr; 85 | Uint8 socket[2]; 86 | } dest, src; 87 | } GCC_ATTRIBUTE(packed); 88 | 89 | // Ethernet header for use with pcap 90 | struct sniff_ethernet { 91 | u_char ether_dhost[ETHER_ADDR_LEN]; // Destination host address 92 | u_char ether_shost[ETHER_ADDR_LEN]; // Source host address 93 | u_short ether_type; // Packet type or length 94 | }; 95 | 96 | // From DosBox 97 | struct packetBuffer { 98 | Bit8u buffer[1024]; 99 | Bit16s packetSize; // Packet size remaining in read 100 | Bit16s packetRead; // Bytes read of total packet 101 | bool inPacket; // In packet reception flag 102 | Bit8u connected; // Connected flag. 0=Not connected, 1=Connected, 2=Requesting address by trying a echo with timeout. 103 | bool waitsize; 104 | //Timer for checking if a client exists. 105 | Bit64u timer; 106 | struct timeval timerlast; 107 | struct timeval timernow; 108 | //End of timer variables. 109 | }; 110 | 111 | // Hack to allow SDLNet pollable pcap socket. Adapted from 112 | // SDLnetselect.c in SDL_Net 113 | struct Pcap_Socket { 114 | int ready; 115 | SOCKET channel; 116 | }; 117 | 118 | // Some globally shared variables 119 | char errbuf[PCAP_ERRBUF_SIZE]; // Buffer for pcap error messages 120 | pcap_t *handle; // Handle for pcap 121 | IPaddress ipxServerIp; // IPAddress for server's listening port 122 | UDPsocket ipxServerSocket; // Listening server socket 123 | packetBuffer connBuffer[SOCKETTABLESIZE]; // DosBOX 124 | Bit8u inBuffer[IPXBUFFERSIZE]; // DosBOX 125 | IPaddress ipconn[SOCKETTABLESIZE]; // Active TCP/IP connection 126 | IPaddress ipconnAssigned[SOCKETTABLESIZE]; // Active TCP/IP connection's assigned IPX address! 127 | Uint32 ipconnNetwork[SOCKETTABLESIZE]; //The network number of the client! 128 | Uint16 port; // UDP port to listen 129 | char device[20]; // Interface name 130 | bool use_llc = true; // Use Logical Link Control (IEEE 802.2) 131 | bool use_ethernetii = false; // Use Logical Link Control (IEEE 802.2) 132 | Uint32 use_IPXnetworknumber = 0; // Used network number for all clients! 133 | 134 | // From DosBox 135 | void UnpackIP(PackedIP ipPack, IPaddress * ipAddr) { 136 | ipAddr->host = ipPack.host; 137 | ipAddr->port = ipPack.port; 138 | } 139 | 140 | // From DosBox 141 | void PackIP(IPaddress ipAddr, PackedIP *ipPack) { 142 | ipPack->host = ipAddr.host; 143 | ipPack->port = ipAddr.port; 144 | } 145 | 146 | // Convert MAC address to printable string 147 | void mac_to_string(const u_char mac[], char *str) 148 | { 149 | sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 150 | } 151 | void ipxnode_to_string(const u_char ipx[], char* str) 152 | { 153 | sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", ipx[0], ipx[1], ipx[2], ipx[3], ipx[4], ipx[5]); 154 | } 155 | 156 | //Below IPX address functions and some reserved addresses copied from UniPCemu. 157 | //result: 1 for OK address. 0 for overflow! NULL and Broadcast and special addresses are skipped automatically. addrsizeleft should be 6 (the size of an IPX address) 158 | //Some reserved IPX addresses for special use (taken from UniPCemu)! 159 | uint8_t ipxbroadcastaddr[6] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; //IPX Broadcast address 160 | uint8_t ipxnulladdr[6] = { 0x00,0x00,0x00,0x00,0x00,0x00 }; //IPX Forbidden NULL address 161 | uint8_t ipx_servernodeaddr[6] = { 0x00,0x00,0x00,0x00,0x00,0x01 }; //IPX server node address! 162 | uint8_t ipx_servernetworknumber[4] = { 0x00,0x00,0x00,0x01 }; //Server network number! 163 | uint8_t incIPXaddr2(uint8_t* ipxaddr, uint8_t addrsizeleft) //addrsizeleft=6 for the address specified 164 | { 165 | uint8_t result; 166 | uint8_t originaladdrsize; 167 | originaladdrsize = addrsizeleft; //How much is left? 168 | if (!addrsizeleft) return 0; //Nothing to allocate anymore? 169 | ++*ipxaddr; //Increase the address! 170 | result = 1; //Default: OK! 171 | if (*ipxaddr == 0) //Overflow? 172 | { 173 | result = incIPXaddr2(--ipxaddr, --addrsizeleft); //Try the next upper byte! 174 | } 175 | addrsizeleft = originaladdrsize; //What were we processing? 176 | if (addrsizeleft == 6) //No overflow for full address? 177 | { 178 | if (memcmp(ipxaddr - 5, &ipxbroadcastaddr, sizeof(ipxbroadcastaddr)) == 0) //Broadcast address? all ones. 179 | { 180 | return incIPXaddr2(ipxaddr, 6); //Increase to the first address, which we'll use! 181 | } 182 | if (memcmp(ipxaddr - 5, &ipxnulladdr, sizeof(ipxnulladdr)) == 0) //Null address? all zeroes. 183 | { 184 | return incIPXaddr2(ipxaddr, addrsizeleft); //Increase to the first address, which we'll use! 185 | } 186 | if (memcmp(ipxaddr - 5, &ipx_servernodeaddr, sizeof(ipx_servernodeaddr)) == 0) //Server address? ~01 187 | { 188 | return incIPXaddr2(ipxaddr, 6); //Increase to the next possible address, which we'll use! 189 | } 190 | } 191 | return result; //Address is OK, if we've not overflown! 192 | } 193 | 194 | //ipxaddr must point to the first byte of the address (it's in big endian format) 195 | uint8_t incIPXaddr(uint8_t* ipxaddr) 196 | { 197 | return incIPXaddr2(&ipxaddr[5], 6); //Increment the IPX address to a valid address from the LSB! 198 | } 199 | 200 | uint8_t IPXaddrused(uint8_t* ipxaddr, Bit16u *ignoreentry) 201 | { 202 | uint8_t rawipxaddr[6]; 203 | Bit16u i; 204 | for (i=0;i> 1) | (srcnetworkcur >> 2) | srcnetworkcur | 6)) 230 | //COMMONNETFILTER 231 | //Source network current or broadcast? 232 | //Destination network current or broadcast? 233 | #define COMMONNETFILTER srcnetworkcur = (((!srcnetwork) ? 1 : 0) | ((srcnetwork == ipconnNetwork[i]) ? 2 : 0) | ((srcnetwork == 0xFFFFFFFF) ? 4 : 0)); \ 234 | dstnetworkcur = (((!dstnetwork) ? 1 : 0) | ((dstnetwork == ipconnNetwork[i]) ? 2 : 0) | ((dstnetwork == 0xFFFFFFFF) ? 4 : 0)); 235 | 236 | void get_ipxaddr(uint8_t *addr, Bit32u host, Bit16u port) //Convert a host:port to IPX address! 237 | { 238 | addr[0] = (host >> 0) & 0xff; 239 | addr[1] = (host >> 8) & 0xff; 240 | addr[2] = (host >> 16) & 0xff; 241 | addr[3] = (host >> 24) & 0xff; 242 | addr[4] = (port & 0xff); 243 | addr[5] = (port >> 8) & 0xff; 244 | } 245 | 246 | // From DosBox ipxserver.cpp - send packet to connected host 247 | void sendIPXPacket(Bit8u *buffer, Bit16s bufSize) { 248 | Bit16u srcport, destport; 249 | Bit32u srchost, desthost; 250 | Bit16u i; 251 | Bits result; 252 | Bit32u srcnetwork, dstnetwork; 253 | Bit8u srcnetworkcur, dstnetworkcur; //Flags reflecting different network conditions 254 | #ifdef DEBUGNW 255 | char ipxdst[20], ipxcur[20]; 256 | uint8_t ipxnode[6]; //IPX node number! 257 | #endif 258 | 259 | UDPpacket outPacket; 260 | outPacket.channel = -1; 261 | outPacket.data = buffer; 262 | outPacket.len = bufSize; 263 | outPacket.maxlen = bufSize; 264 | IPXHeader *tmpHeader; 265 | tmpHeader = (IPXHeader *)buffer; 266 | #ifdef DEBUGNW 267 | ipxdst[0] = ipxcur[0] = (char)0; //Init! 268 | #endif 269 | 270 | srchost = tmpHeader->src.addr.byIP.host; 271 | desthost = tmpHeader->dest.addr.byIP.host; 272 | 273 | srcport = tmpHeader->src.addr.byIP.port; 274 | destport = tmpHeader->dest.addr.byIP.port; 275 | 276 | srcnetwork = SDLNet_Read32(tmpHeader->src.network); //Source network! 277 | dstnetwork = SDLNet_Read32(tmpHeader->dest.network); //Destination network! 278 | 279 | srcnetworkcur = dstnetworkcur = 0; //Init! 280 | 281 | if((desthost == 0xffffffff) /* && (destport == 0xFFFF)*/) { //IPX node broadcast (this is officially both the host and port part having all bits set)? 282 | // Broadcast 283 | for(i=0;i box, IPX len=%i\n", regPacket.len); 375 | 376 | //Also let the host network know that we allocated if on a Ethernet II network! 377 | if (use_ethernetii) //Ethernet II used? 378 | { 379 | // Create and send packet received from DosBox to the real network 380 | memset(ðernet, 0, sizeof(ethernet)); //Clear! 381 | 382 | ethernet[0] = ethernet[1] = ethernet[2] = ethernet[3] = ethernet[4] = ethernet[5] = 0xFF; //Destination: broadcast! 383 | memcpy(ethernet + 6, regHeader.src.addr.byNode.node, 6); //Source: node! 384 | ethernet[12] = 0x81; 385 | ethernet[13] = 0x37; //IPX over ethernet! 386 | 387 | //Slight modification in the packet for the ACK on the host network! From assigned address to server node address to register (if any is listening)! 388 | SDLNet_Write32(ipconnNetwork[client], regHeader.src.network); 389 | PackIP(assignedAddr, ®Header.src.addr.byIP); 390 | SDLNet_Write16(0x2, regHeader.src.socket); 391 | 392 | memcpy(®Header.dest.network,&ipx_servernetworknumber,4); 393 | memcpy(®Header.dest.addr.byNode.node,&ipx_servernodeaddr,6); //Send to the a packet server registration, if any is listening and/or allocating! 394 | SDLNet_Write16(0x2, regHeader.dest.socket); 395 | 396 | // IPX 397 | memcpy(ðernet[ETHER_HEADER_LEN], regPacket.data, regPacket.len); 398 | sendlen = ETHER_HEADER_LEN + regPacket.len; //Length to send! 399 | 400 | // Actual send 401 | if (pcap_sendpacket(handle, ðernet[0], sendlen) != 0) 402 | { 403 | printf("Error sending the packet: %s\n", pcap_geterr(handle)); 404 | } 405 | else 406 | { 407 | printf("ACK -> real, IPX len=%i\n", regPacket.len); 408 | } 409 | } 410 | } 411 | 412 | // Adjusted from DosBox ipxserver.cpp - check a new connection for availability by echo. 413 | static void requestClientEcho(int client) { 414 | Bit32u sendlen; 415 | IPaddress clientAddr; 416 | IPaddress assignedAddr; 417 | IPXHeader regHeader; 418 | UDPpacket regPacket; 419 | unsigned char ethernet[1500]; 420 | memcpy(&clientAddr, &ipconn[client], sizeof(clientAddr)); //The clients host address and port! 421 | memcpy(&assignedAddr, &ipconnAssigned[client], sizeof(assignedAddr)); //The clients assigned address and port! 422 | 423 | SDLNet_Write16(0xffff, regHeader.checkSum); 424 | SDLNet_Write16(sizeof(regHeader), regHeader.length); 425 | 426 | //Send it back to the client's requested address! This will also where it's returned to! 427 | SDLNet_Write32(ipconnNetwork[client], regHeader.src.network); 428 | PackIP(assignedAddr, ®Header.src.addr.byIP); 429 | SDLNet_Write16(0x2, regHeader.src.socket); 430 | 431 | //And send from us (and received from them) as a broadcast! 432 | SDLNet_Write32(ipconnNetwork[client], regHeader.dest.network); 433 | memset(®Header.dest.addr.byNode.node, 0xFF, 6); //Broadcast it! 434 | SDLNet_Write16(0x2, regHeader.dest.socket); 435 | regHeader.transControl = 0; 436 | regHeader.pType = 0; //Echo request! 437 | 438 | 439 | regPacket.data = (Uint8*)®Header; 440 | regPacket.len = sizeof(regHeader); 441 | regPacket.maxlen = sizeof(regHeader); 442 | regPacket.address = clientAddr; //Client's real address and port it's listening on! 443 | 444 | printf("alloc request -> box, IPX len=%i\n", regPacket.len); 445 | 446 | //Send to all Dosbox-clients to detect if they're used! 447 | sendIPXPacket(regPacket.data, regPacket.len); //Send to all Dosbox clients! 448 | 449 | //Also let the host network know that we are trying to allocate if on a Ethernet II network! 450 | if (use_ethernetii) //Ethernet II used? 451 | { 452 | // Create and send packet received from DosBox to the real network 453 | memset(ðernet, 0, sizeof(ethernet)); //Clear! 454 | 455 | ethernet[0] = ethernet[1] = ethernet[2] = ethernet[3] = ethernet[4] = ethernet[5] = 0xFF; //Destination: broadcast! 456 | ethernet[6] = ethernet[7] = ethernet[8] = ethernet[9] = ethernet[10] = ethernet[11] = 0xFF; //Source: broadcast! 457 | ethernet[12] = 0x81; 458 | ethernet[13] = 0x37; //IPX over ethernet! 459 | 460 | // IPX 461 | memcpy(ðernet[ETHER_HEADER_LEN], regPacket.data, regPacket.len); 462 | sendlen = ETHER_HEADER_LEN + regPacket.len; //Length to send! 463 | 464 | // Actual send 465 | if (pcap_sendpacket(handle, ðernet[0], sendlen) != 0) 466 | { 467 | printf("Error sending the packet: %s\n", pcap_geterr(handle)); 468 | } 469 | else 470 | { 471 | printf("alloc request -> real, IPX len=%i\n", regPacket.len); 472 | } 473 | } 474 | 475 | //Initialize timers to setup a timeout! 476 | gettimeofday(&connBuffer[client].timernow, NULL); //Init current time for timekeeping! 477 | memcpy(&connBuffer[client].timerlast, &connBuffer[client].timernow, sizeof(connBuffer[client].timerlast)); //Copy to make them equal! 478 | connBuffer[client].timer = 0; //Initialize to nothing ticked yet! 479 | } 480 | 481 | // From DosBox ipxserver.cpp - receive packet and hand over to other clients 482 | // Modified to also send the packet to real interface using pcap 483 | void IPX_ServerLoop() { 484 | UDPpacket inPacket; 485 | IPaddress tmpAddr; 486 | uint8_t ipxaddr[6]; 487 | 488 | Bit16u i; 489 | Bit32u host; 490 | Bits result; 491 | Bit32u sendlen; 492 | 493 | inPacket.channel = -1; 494 | inPacket.data = &inBuffer[0]; 495 | inPacket.maxlen = IPXBUFFERSIZE; 496 | 497 | result = SDLNet_UDP_Recv(ipxServerSocket, &inPacket); 498 | if (result != 0) { 499 | // Check to see if incoming packet is a registration packet 500 | // For this, I just spoofed the echo protocol packet designation 0x02 501 | IPXHeader *tmpHeader; 502 | tmpHeader = (IPXHeader *)&inBuffer[0]; 503 | ++tmpHeader->transControl; //Received, so increase the transport control field! 504 | if (tmpHeader->transControl>=16) //16th hop discards? 505 | { 506 | return; //Discard! 507 | } 508 | if (memcmp(&tmpHeader->src.addr.byNode.node,&ipxbroadcastaddr,6)==0) //Broadcast source is forbidden? 509 | { 510 | return; //Discard! 511 | } 512 | 513 | if (SDLNet_Read32(tmpHeader->src.network)==0) { //Own network needs patching? 514 | for(i=0;isrc.network); //Fixup source network to client network! 518 | } 519 | } 520 | } 521 | } 522 | 523 | // Check to see if echo packet 524 | if(SDLNet_Read16(tmpHeader->dest.socket) == 0x2) { 525 | // Null destination node means its a server registration packet 526 | if(tmpHeader->dest.addr.byIP.host == 0x0) { 527 | UnpackIP(tmpHeader->src.addr.byIP, &tmpAddr); 528 | for(i=0;i box, IPX len=%i\n", inPacket.len); 584 | 585 | 586 | // Create and send packet received from DosBox to the real network 587 | unsigned char ethernet[1500]; 588 | memset(ðernet, 0, sizeof(ethernet)); //Clear! 589 | --tmpHeader->transControl; //Received, don't increase the transport control field to count as a passthrough and let the receiving end apply this instead! 590 | 591 | if (!use_ethernetii) //Not ethernet II? 592 | { 593 | // Ethernet source and destination MACs are replicated from IPX header 594 | memcpy(ethernet, tmpHeader->dest.addr.byNode.node, 6); 595 | memcpy(ethernet + 6, tmpHeader->src.addr.byNode.node, 6); 596 | 597 | // Ethernet packet length 598 | u_short ether_packet_len = inPacket.len + (use_llc ? ENCAPSULE_LEN : 0); 599 | ether_packet_len = (ether_packet_len >> 8) | (ether_packet_len << 8); // Swap endianess 600 | memcpy(ðernet[ETHER_ADDR_LEN * 2], ðer_packet_len, sizeof(ether_packet_len)); 601 | 602 | // IPX over IP 603 | if (use_llc) { 604 | ethernet[ETHER_HEADER_LEN + 0] = 0xe0; 605 | ethernet[ETHER_HEADER_LEN + 1] = 0xe0; 606 | ethernet[ETHER_HEADER_LEN + 2] = 0x03; 607 | } 608 | 609 | // IPX 610 | memcpy(ðernet[ETHER_HEADER_LEN + (use_llc ? ENCAPSULE_LEN : 0)], inPacket.data, inPacket.len); 611 | sendlen = ETHER_HEADER_LEN + (use_llc ? ENCAPSULE_LEN : 0) + inPacket.len; //Length to send! 612 | } 613 | else //Ethernet II? 614 | { 615 | ethernet[0] = ethernet[1] = ethernet[2] = ethernet[3] = ethernet[4] = ethernet[5] = 0xFF; //Destination: broadcast! 616 | memcpy(ethernet + 6, tmpHeader->src.addr.byNode.node, 6); //Source: node! 617 | ethernet[12] = 0x81; 618 | ethernet[13] = 0x37; //IPX over ethernet! 619 | 620 | // IPX 621 | memcpy(ðernet[ETHER_HEADER_LEN], inPacket.data, inPacket.len); 622 | sendlen = ETHER_HEADER_LEN + inPacket.len; //Length to send! 623 | } 624 | 625 | // Actual send 626 | if (pcap_sendpacket(handle, ðernet[0], sendlen) != 0) 627 | { 628 | printf("Error sending the packet: %s\n", pcap_geterr(handle)); 629 | } 630 | else 631 | { 632 | printf("box -> real, IPX len=%i\n", inPacket.len); 633 | } 634 | } 635 | } 636 | 637 | // From DosBox ipxserver.cpp, stop the ipxnet server 638 | void IPX_StopServer() { 639 | SDLNet_UDP_Close(ipxServerSocket); 640 | } 641 | 642 | // From DosBox ipxserver.cpp, start the ipxnet server 643 | bool IPX_StartServer(Bit16u portnum) { 644 | Bit16u i; 645 | 646 | if(!SDLNet_ResolveHost(&ipxServerIp, NULL, portnum)) { 647 | 648 | ipxServerSocket = SDLNet_UDP_Open(portnum); 649 | if(!ipxServerSocket) return false; 650 | 651 | for(i=0;ilen >= (14 + 3))) 673 | { 674 | const struct sniff_ethernet* ethernet = (struct sniff_ethernet*)(packet); 675 | mac_to_string(ethernet->ether_shost, &smac[0]); 676 | mac_to_string(ethernet->ether_dhost, &dmac[0]); 677 | 678 | #ifdef DEBUG 679 | printf("Captured packet, len=%d, src=%s, dest=%s, ether_type=%i\n", header.len, smac, dmac, ethernet->ether_type); 680 | #endif 681 | 682 | // Send to DOSBox 683 | IPXHeader* tmpHeader = (IPXHeader*)(packet + ETHER_HEADER_LEN + (use_llc ? ENCAPSULE_LEN : 0)); 684 | ++tmpHeader->transControl; //Received, so increase the transport control field! 685 | if (tmpHeader->transControl>=16) //16th hop discards? 686 | { 687 | return; //Discard the packet! 688 | } 689 | if (memcmp(&tmpHeader->src.addr.byNode.node,&ipxbroadcastaddr,6)==0) //Broadcast source is forbidden? 690 | { 691 | return; //Discard! 692 | } 693 | 694 | sendIPXPacket((Bit8u*)tmpHeader, header->len - (ETHER_HEADER_LEN + (use_llc ? ENCAPSULE_LEN : 0))); 695 | 696 | printf("real -> box , IPX len=%i\n", header->len - (ETHER_HEADER_LEN + (use_llc ? ENCAPSULE_LEN : 0))); 697 | } 698 | } 699 | else //Ethernet II? 700 | { 701 | if (pcap_next_ex(handle,&header,&packet)<=0) return; //Poll manually! 702 | if ((packet != 0) && (header->len >= (ETHER_HEADER_LEN + 30))) //Ethernet Header and IPX header minimum length? 703 | { 704 | if ((packet[12] == 0x81) && (packet[13] == 0x37)) //IPX? 705 | { 706 | // Create and send packet received from DosBox to the real network 707 | IPaddress tmpAddr; 708 | 709 | //Check for a registration packet. 710 | // For this, I just spoofed the echo protocol packet designation 0x02 711 | IPXHeader* tmpHeader; 712 | tmpHeader = (IPXHeader*)&packet[ETHER_HEADER_LEN]; //The IPX packet! 713 | ++tmpHeader->transControl; //Received, so increase the transport control field! 714 | if (tmpHeader->transControl>=16) //16th hop discards the packet! 715 | { 716 | return; //Discard the packet! 717 | } 718 | if (memcmp(&tmpHeader->src.addr.byNode.node,&ipxbroadcastaddr,6)==0) //Broadcast source is forbidden? 719 | { 720 | return; //Discard! 721 | } 722 | 723 | 724 | // Check to see if echo packet 725 | if (SDLNet_Read16(tmpHeader->dest.socket) == 0x2) { 726 | // Our destination node means its a server registration already used packet if allocating. 727 | for (i = 0; i < SOCKETTABLESIZE; i++) { 728 | if (connBuffer[i].connected) { //Connected or requesting? 729 | UnpackIP(tmpHeader->src.addr.byIP, &tmpAddr); //The requested address! 730 | if ((ipconnAssigned[i].host == tmpAddr.host) && (ipconnAssigned[i].port == tmpAddr.port) && (connBuffer[i].connected == 2)) { //Requesting an answer to detect in-use? 731 | //Convert IPX node number to a byte array, increment and try the next in range! 732 | memcpy(&ipxaddr[0], &ipconnAssigned[i].host, 4); //Host! 733 | memcpy(&ipxaddr[4], &ipconnAssigned[i].port, 2); //Port! 734 | incIPXaddr(&ipxaddr[0]); //Next available address! 735 | for (;IPXaddrused(&ipxaddr[0],&i);) //Skip addresses that are being requested or used! 736 | { 737 | incIPXaddr(&ipxaddr[0]); //Next available address! 738 | } 739 | memcpy(&ipconnAssigned[i].host, &ipxaddr[0], 4); //Host! 740 | memcpy(&ipconnAssigned[i].port, &ipxaddr[4], 2); //Port! 741 | PackIP(ipconnAssigned[i], &tmpHeader->src.addr.byIP); 742 | requestClientEcho(i); //Send a new client echo packet on the hosts to try the next IPX node number! 743 | } 744 | } 745 | } 746 | } 747 | 748 | //Normal packet! 749 | const struct sniff_ethernet* ethernet = (struct sniff_ethernet*)(packet); 750 | mac_to_string(ethernet->ether_shost, &smac[0]); 751 | mac_to_string(ethernet->ether_dhost, &dmac[0]); 752 | 753 | #ifdef DEBUG 754 | printf("Captured packet, len=%d, src=%s, dest=%s, ether_type=%i\n", header.len, smac, dmac, ethernet->ether_type); 755 | #endif 756 | // Send to DOSBox 757 | tmpHeader = (IPXHeader*)(packet + ETHER_HEADER_LEN); 758 | sendIPXPacket((Bit8u*)tmpHeader, header->len - (ETHER_HEADER_LEN)); 759 | printf("real -> box , IPX len=%i\n", header->len - (ETHER_HEADER_LEN)); 760 | } 761 | 762 | //Check for timers! 763 | for (i = 0; i < SOCKETTABLESIZE; i++) { 764 | if (connBuffer[i].connected == 2) { //Connected and waiting? 765 | memcpy(&connBuffer[i].timerlast, &connBuffer[i].timernow, sizeof(connBuffer[i].timerlast)); //Copy for checking difference! 766 | gettimeofday(&connBuffer[i].timernow, NULL); //Get time of day! 767 | connBuffer[i].timer += ((connBuffer[i].timernow.tv_sec * 1000000) + connBuffer[i].timernow.tv_usec) - ((connBuffer[i].timerlast.tv_sec * 1000000) + connBuffer[i].timerlast.tv_usec); //Time what's elapsed! 768 | if (connBuffer[i].timer >= ALLOCATE_IPXNODE_ECHO_TIMEOUT) //Timer elapsed without reply? The IPX node number isn't deemed to be used! 769 | { 770 | connBuffer[i].connected = 1; //Connected using the allocated address! 771 | ackClient(i); //Acknowledge the client! 772 | } 773 | } 774 | } 775 | } 776 | } 777 | } 778 | 779 | // Clean shutdown, used by signal 780 | void clean_shutdown(int signum) 781 | { 782 | printf("\nClean shutdown\n"); 783 | pcap_close(handle); 784 | IPX_StopServer(); 785 | exit(signum); 786 | } 787 | 788 | // Main program 789 | int main(int argc, char *argv[]) 790 | { 791 | int port = 213; 792 | int timeout = 0; 793 | bool help = false; 794 | int c; 795 | bool networkspecified = false; 796 | 797 | while ((c = getopt (argc, argv, "p:n:t:rhe")) != -1) 798 | switch (c) 799 | { 800 | case 'p': 801 | port = atoi(optarg); 802 | break; 803 | case 't': 804 | timeout = atoi(optarg); 805 | case 'n': 806 | use_IPXnetworknumber = atoi(optarg); 807 | networkspecified = true; //Specified! 808 | break; 809 | case 'r': 810 | use_llc = false; 811 | break; 812 | case 'e': 813 | use_ethernetii = true; //Use Ethernet II encapsulation and server! 814 | break; 815 | case 'h': 816 | help = true; 817 | break; 818 | case '?': 819 | exit(1); 820 | default: 821 | abort(); 822 | } 823 | 824 | // Command line parameters 825 | if (optind+1 != argc || help) 826 | { 827 | errx(1, "Usage: %s IF [-p PORT] [-t TIMEOUT]\n\n" 828 | "Forwards IPX traffic between network interface " 829 | "IF where the real\ncomputers are located and DOSBox " 830 | "IPXNET.\n\nParameters:\n" 831 | " -p UDP port where DOSBox connects to, defaults to 213\n" 832 | " -t Packet read timeout in milliseconds\n" 833 | " (Screamer Rally is unplayable without this option)\n" 834 | " -n IPX network number to use, defaults to 0\n" 835 | " -r Use Novell raw IEEE 802.3 instead of LLC (IEEE 802.2)\n" 836 | " -e Use Ethernet II instead of 802.3/802.2", 837 | argv[0]); 838 | } 839 | 840 | strncpy(device, argv[optind], sizeof(device)); 841 | 842 | // Open interface that has real DOS machine, in promiscuous mode 843 | handle = pcap_open_live(device, BUFSIZ, 1, timeout, errbuf); 844 | if (!handle) 845 | { 846 | printf("Couldn't open device %s for pcap: %s\n", device, errbuf); 847 | return 1; 848 | } 849 | else 850 | { 851 | printf("Opened device %s for pcap, " 852 | "with a packet read timeout of %i\n" 853 | , device, timeout); 854 | } 855 | 856 | // Start DosBox IPX server 857 | if (IPX_StartServer(port)) 858 | { 859 | printf("DosBox IPX server started at port %i\n", port); 860 | } 861 | else 862 | { 863 | printf("Couldn't start DosBox IPX server\n"); 864 | return 1; 865 | } 866 | 867 | // Craft an SDL_net pollable pcap socket 868 | struct Pcap_Socket sdlnet_pcap = {0, pcap_get_selectable_fd(handle)}; 869 | if (sdlnet_pcap.channel == PCAP_ERROR) { 870 | errx(1, "Unable to get fd from pcap device\n"); 871 | } 872 | 873 | // Create SDL_net socket set 874 | SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(2); 875 | if(!socketSet) { 876 | errx(1, "SDLNet_AllocSocketSet: %s\n", SDLNet_GetError()); 877 | } 878 | if (SDLNet_UDP_AddSocket(socketSet, ipxServerSocket) == -1) { 879 | errx(1, "SDLNet_AddSocket: %s\n", SDLNet_GetError()); 880 | } 881 | if (SDLNet_UDP_AddSocket(socketSet, &sdlnet_pcap) == -1) { 882 | errx(1, "SDLNet_AddSocket: %s\n", SDLNet_GetError()); 883 | } 884 | 885 | if (networkspecified) //Network number specified by the user? 886 | { 887 | printf("Using network number %i\n", use_IPXnetworknumber); //Display the network number used! 888 | } 889 | 890 | printf("\nYou can now write somewhere, on some DOSBox(es):\nIPXNET CONNECT %i\n", port); 891 | printf("Then, start IPX networking on real DOS computer(s) connected to %s.\n", device); 892 | printf("Now you can start playing IPX games between them.\n\n"); 893 | 894 | // Use CTRL-C or SIGTERM to exit 895 | signal(SIGINT, clean_shutdown); 896 | signal(SIGTERM, clean_shutdown); 897 | 898 | // Main loop for exchanging packets and accepting connections 899 | for(;;) 900 | { 901 | SDLNet_CheckSockets(socketSet, -1); 902 | if (sdlnet_pcap.ready) { 903 | pcap_to_dosbox(); 904 | // Setting socket status manually to non-ready 905 | // because read it outside SDLNet. 906 | sdlnet_pcap.ready = 0; 907 | } 908 | else if (use_ethernetii) 909 | { 910 | pcap_to_dosbox(); //Manual update! 911 | } 912 | if (SDLNet_SocketReady(ipxServerSocket)) { 913 | IPX_ServerLoop(); 914 | } 915 | } 916 | 917 | return 0; 918 | } 919 | --------------------------------------------------------------------------------