build standalone ipx utilities without ncpfs private headers

This commit is contained in:
Mario Fetka
2026-04-29 19:17:02 +02:00
parent 80f13f2193
commit ea1cadb737
32 changed files with 11006 additions and 666 deletions

380
INSTALL
View File

@@ -0,0 +1,380 @@
Installation Instructions
*************************
Basic Installation
==================
The following shell commands:
test -f configure || ./bootstrap
./configure
make
make install
should configure, build, and install this package. The first line,
which bootstraps, is intended for developers; when building from
distribution tarballs it does nothing and can be skipped. A package
might name the bootstrapping script differently; if the name is
autogen.sh, for example, the first line should say ./autogen.sh
instead of ./bootstrap.
The following more-detailed instructions are generic; see the
README file for instructions specific to this package. Some packages
provide this INSTALL file but do not implement all of the features
documented below. The lack of an optional feature in a given package is
not necessarily a bug. More recommendations for GNU packages can be
found in the GNU Coding Standards.
Many packages have scripts meant for developers instead of ordinary
builders, as they may use developer tools that are less commonly
installed, or they may access the network, which has privacy
implications. These scripts attempt to bootstrap by building the
configure script and related files, possibly using developer tools or
the network. Because the output of bootstrapping is system-independent,
it is normally run by a package developer so that its output can be put
into the distribution tarball and ordinary builders and users need not
bootstrap. Some packages have commands like ./autopull.sh and
./autogen.sh that you can run instead of ./bootstrap, for more
fine-grained control over bootstrapping.
The configure script attempts to guess correct values for various
system-dependent variables used during compilation. It uses those
values to create a Makefile in each directory of the package. It may
also create one or more .h files containing system-dependent
definitions. Finally, it creates a script config.status that you can
run in the future to recreate the current configuration, and a file
config.log containing output useful for debugging configure.
It can also use an optional file (typically called config.cache and
enabled with --cache-file=config.cache or simply -C) that saves the
results of its tests to speed up reconfiguring. Caching is disabled by
default to prevent problems with accidental use of stale cache files.
If you need to do unusual things to compile the package, please try
to figure out how configure could check whether to do them, and mail
diffs or instructions to the address given in the README so they can
be considered for the next release. If you are using the cache, and at
some point config.cache contains results you dont want to keep, you
may remove or edit it.
The autoconf program generates configure from the file
configure.ac. Normally you should edit configure.ac instead of
editing configure directly.
The simplest way to compile this package is:
1. cd to the directory containing the packages source code.
2. If this is a developer checkout and file configure does not yet
exist, run the bootstrapping script (typically ./bootstrap or
./autogen.sh) to bootstrap and create the file. You may need
special developer tools and network access to bootstrap, and the
network access may have privacy implications.
3. Type ./configure to configure the package for your system. This
might take a while. While running, configure prints messages
telling which features it is checking for.
4. Type make to compile the package.
5. Optionally, type make check to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
6. Type make install to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the make install phase executed with root
privileges.
7. Optionally, type make installcheck to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior make install required
root privileges, verifies that the installation completed
correctly.
8. You can remove the program binaries and object files from the
source code directory by typing make clean. To also remove the
files that configure created (so you can compile the package for
a different kind of computer), type make distclean. There is
also a make maintainer-clean target, but that is intended mainly
for the packages developers. If you use it, you may have to
bootstrap again.
9. If the package follows the GNU Coding Standards, you can type make
uninstall to remove the installed files.
Installation Prerequisites
==========================
Installation requires a POSIX-like environment with a shell and at
least the following standard utilities:
awk cat cp diff echo expr false ls mkdir mv printf pwd rm rmdir sed
sort test tr
This packages installation may need other standard utilities such as
grep, make, sleep and touch, along with compilers like gcc.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the configure script does not know about. Run ./configure --help
for details on some of the pertinent environment variables.
You can give configure initial values for configuration parameters
by setting variables in the command line or in the environment. Here is
an example:
./configure CC=gcc CFLAGS=-g LIBS=-lposix
See “Defining Variables” for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each system in their own
directory. To do this, you can use GNU make. cd to the directory
where you want the object files and executables to go and run the
configure script. configure automatically checks for the source
code in the directory that configure is in and in ... This is known
as a “VPATH” build.
With a non-GNU make, it is safer to compile the package for one
system at a time in the source code directory. After you have installed
the package for one system, use make distclean before reconfiguring
for another system.
Some platforms, notably macOS, support “fat” or “universal” binaries,
where a single binary can execute on different architectures. On these
platforms you can configure and compile just once, with options specific
to that platform.
Installation Names
==================
By default, make install installs the packages commands under
/usr/local/bin, include files under /usr/local/include, etc. You
can specify an installation prefix other than /usr/local by giving
configure the option --prefix=PREFIX, where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option --exec-prefix=PREFIX to configure, the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like --bindir=DIR to specify different values for particular
kinds of files. Run configure --help for a list of the directories
you can set and what kinds of files go in them. In general, the default
for these options is expressed in terms of ${prefix}, so that
specifying just --prefix will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to configure; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
make install command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, make install
prefix=/alternate/directory will choose an alternate location for all
directory configuration variables that were expressed in terms of
${prefix}. Any directories that were specified during configure,
but not in terms of ${prefix}, must each be overridden at install time
for the entire installation to be relocated. The approach of makefile
variable overrides for each directory variable is required by the GNU
Coding Standards, and ideally causes no recompilation. However, some
platforms have known limitations with the semantics of shared libraries
that end up requiring recompilation when using this method, particularly
noticeable in packages that use GNU Libtool.
The second method involves providing the DESTDIR variable. For
example, make install DESTDIR=/alternate/directory will prepend
/alternate/directory before all installation names. The approach of
DESTDIR overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of ${prefix}
at configure time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving configure the
option --program-prefix=PREFIX or --program-suffix=SUFFIX.
Some packages pay attention to --enable-FEATURE and
--disable-FEATURE options to configure, where FEATURE indicates an
optional part of the package. They may also pay attention to
--with-PACKAGE and --without-PACKAGE options, where PACKAGE is
something like gnu-ld. ./configure --help should mention the
--enable-... and --with-... options that the package recognizes.
Some packages offer the ability to configure how verbose the
execution of make will be. For these packages, running ./configure
--enable-silent-rules sets the default to minimal output, which can be
overridden with make V=1; while running ./configure
--disable-silent-rules sets the default to verbose, which can be
overridden with make V=0.
Specifying a System Type
========================
By default configure builds for the current system. To create
binaries that can run on a different system type, specify a
--host=TYPE option along with compiler variables that specify how to
generate object code for TYPE. For example, to create binaries intended
to run on a 64-bit ARM processor:
./configure --host=aarch64-linux-gnu \
CC=aarch64-linux-gnu-gcc \
CXX=aarch64-linux-gnu-g++
If done on a machine that can execute these binaries (e.g., via
qemu-aarch64, $QEMU_LD_PREFIX, and Linuxs binfmt_misc
capability), the build behaves like a native build. Otherwise it is a
cross-build: configure will make cross-compilation guesses instead of
running test programs, and make check will not work.
A system type can either be a short name like mingw64, or a
canonical name like x86_64-pc-linux-gnu. Canonical names have the
form CPU-COMPANY-SYSTEM where SYSTEM is either OS or KERNEL-OS. To
canonicalize and validate a system type, you can run the command
config.sub, which is often squirreled away in a subdirectory like
build-aux. For example:
$ build-aux/config.sub arm64-linux
aarch64-unknown-linux-gnu
$ build-aux/config.sub riscv-lnx
Invalid configuration 'riscv-lnx': OS 'lnx' not recognized
You can look at the config.sub file to see which types are recognized.
If the file is absent, this package does not need the system type.
If configure fails with the diagnostic “cannot guess build type”.
config.sub did not recognize your systems type. In this case, first
fetch the newest versions of these files from the GNU config package
(https://savannah.gnu.org/projects/config). If that fixes things,
please report it to the maintainers of the package containing
configure. Otherwise, you can try the configure option --build=TYPE
where TYPE comes close to your system type; also, please report the
problem to <config-patches@gnu.org>.
For more details about configuring system types, see the Autoconf
documentation.
Sharing Defaults
================
If you want to set default values for configure scripts to share,
you can create a site shell script called config.site that gives
default values for variables like CC, cache_file, and prefix.
configure looks for PREFIX/share/config.site if it exists, then
PREFIX/etc/config.site if it exists. Or, you can set the
CONFIG_SITE environment variable to the location of the site script.
A warning: not all configure scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to configure. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the configure command line, using VAR=value. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for CONFIG_SHELL due to an
Autoconf limitation. Until the limitation is lifted, you can use this
workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
configure Invocation
======================
configure recognizes the following options to control how it
operates.
--help
-h
Print a summary of all of the options to configure, and exit.
--help=short
--help=recursive
Print a summary of the options unique to this packages
configure, and exit. The short variant lists options used only
in the top level, while the recursive variant lists options also
present in any nested packages.
--version
-V
Print the version of Autoconf used to generate the configure
script, and exit.
--cache-file=FILE
Enable the cache: use and save the results of the tests in FILE,
traditionally config.cache. FILE defaults to /dev/null to
disable caching.
--config-cache
-C
Alias for --cache-file=config.cache.
--srcdir=DIR
Look for the packages source code in directory DIR. Usually
configure can determine that directory automatically.
--prefix=DIR
Use DIR as the installation prefix. See “Installation Names” for
more details, including other options available for fine-tuning the
installation locations.
--host=TYPE
Build binaries for system TYPE. See “Specifying a System Type”.
--enable-FEATURE
--disable-FEATURE
Enable or disable the optional FEATURE. See “Optional Features”.
--with-PACKAGE
--without-PACKAGE
Use or omit PACKAGE when building. See “Optional Features”.
--quiet
--silent
-q
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to /dev/null (any error
messages will still be shown).
--no-create
-n
Run the configure checks, but stop before creating any output
files.
configure also recognizes several environment variables, and accepts
some other, less widely useful, options. Run configure --help for
more details.
Copyright notice
================
Copyright © 19941996, 19992002, 20042017, 20202025 Free Software
Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.

View File

@@ -1,34 +1,53 @@
AM_CFLAGS = -Wall -Wextra
bin_PROGRAMS = \
sbin_PROGRAMS = \
ipx_configure \
ipx_interface \
ipx_internal_net \
ipx_route
ipx_route \
ipx_cmd \
ipxdump \
ipxparse
ipx_configure_SOURCES = \
src/ipx_configure.c
ipx_interface_SOURCES = \
src/ipxutil.c \
src/ipx_interface.c
ipx_internal_net_SOURCES = \
src/ipxutil.c \
src/ipx_internal_net.c
ipx_route_SOURCES = \
src/ipxutil.c \
src/ipx_route.c
ipx_cmd_SOURCES = \
src/ipx_cmd.c
ipxdump_SOURCES = \
tools/ipxutil.c \
tools/ipxdump.c
ipxparse_SOURCES = \
tools/ipxutil.c \
tools/ipxparse.c
man_MANS = \
docs/ipx_configure.8 \
docs/ipx_interface.8 \
docs/ipx_internal_net.8 \
docs/ipx_route.8
docs/ipx_route.8 \
docs/ipx_cmd.8
samples_files = \
Samples/ipxrcv.c \
Samples/ipxsend.c \
Samples/rip.c \
Samples/sap.c
Samples/sap.c \
Samples/samples.h
EXTRA_DIST = \
$(man_MANS) \

45
README
View File

@@ -68,3 +68,48 @@ There are three files in /proc/net/ipx that relate to IPX:
interface contains the list of IPX interfaces.
route contains the list of IPX routes.
socket the list of IPX sockets in use.
This is a VERY stupid packet sniffer for IPX ethernet packets.
=============================================
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! S E C U R I T Y W A R N I N G ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
=============================================
If you are using unencrypted passwords, and use this tool to send a
dump to somebody else or store it on a computer, you might very well
store passwords there. So, be VERY careful! This is exactly the kind
of tools Novell designed the encrypted passwords for (or against).
I hacked it together to be able to help people with problems with
ncpfs. The socket handling was taken from Statnet-2.0.
You can use it to watch commercial NetWare clients when they talk to
servers. I divided the program into 2 parts, ipxdump and ipxparse.
ipxdump simply pumps all the IPX frames it receives to stdout.
If you use ipxdump to watch a workstation, you can use the simple
filter function ipxdump provides. You can call ipxdump with the node
address of the workstation you want to watch. This way only the
packets this workstation sends and receives are monitored. As an
example, I call ipxdump as
./ipxdump 00001B038B11
to look at my 286/10MHz test 'workstation'. ipxdump still generates
huge amounts of data, so you should be very careful to start it just
before you perform the operation (such as file creation for OS/2
clients with NW4.1 as a server, or a 'dir' on a directory with long
and short file names, or an encrypted password change ;-)) and stop it
directly after that. And, please gzip -9 and uuencode it before you
send it to anybody.
ipxparse will eventually take apart the dump that ipxdump
generates. They can as well be used in a pipe. Currently ipxparse does
not do anything sensible, but that will definitely change.
Volker Lendecke
<lendecke@namu01.gwdg.de>

View File

@@ -1,22 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netipx/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include "samples.h"
int main(int argc, char **argv)
{
struct sockaddr_ipx sipx;
int s;
int rc;
char msg[100];
int len;
struct sockaddr_ipx sipx;
int s;
int rct;
char msg[100];
socklen_t len;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
if (s < 0)
{
perror("IPX: socket: ");
exit(-1);
}
@@ -25,25 +19,25 @@ int main(int argc, char **argv)
sipx.sipx_network = 0;
sipx.sipx_port = htons(0x5000);
sipx.sipx_type = 17;
len = sizeof(sipx);
rc = bind(s, (struct sockaddr *)&sipx, sizeof(sipx));
if (rc < 0) {
rc = bind(s, (struct sockaddr *) &sipx, sizeof(sipx));
if (rc < 0)
{
perror("IPX: bind: ");
exit(-1);
}
msg[0] = '\0';
rc = recvfrom(s, msg, sizeof(msg), 0, (struct sockaddr *)&sipx, &len);
if (rc < 0) {
len = sizeof(sipx);
rc = recvfrom(s, msg, sizeof(msg), 0, (struct sockaddr *) &sipx, &len);
if (rc < 0)
{
perror("IPX: recvfrom: ");
}
printf("From %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
(unsigned long)ntohl(sipx.sipx_network),
sipx.sipx_node[0], sipx.sipx_node[1],
sipx.sipx_node[2], sipx.sipx_node[3],
sipx.sipx_node[4], sipx.sipx_node[5],
ntohs(sipx.sipx_port));
printf("From %08X:%02X%02X%02X%02X%02X%02X:%04X\n",
(unsigned long)ntohl(sipx.sipx_network),
sipx.sipx_node[0], sipx.sipx_node[1],
sipx.sipx_node[2], sipx.sipx_node[3],
sipx.sipx_node[4], sipx.sipx_node[5],
ntohl(sipx.sipx_port));
printf("\tGot \"%s\"\n", msg);
return 0;
}

View File

@@ -1,22 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netipx/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include "samples.h"
int main(int argc, char **argv)
{
struct sockaddr_ipx sipx;
int s;
int rc;
char msg[100] = "Hello world!";
int len = sizeof(sipx);
struct sockaddr_ipx sipx;
int s;
int rc;
char msg[100] = "Hello world!";
socklen_t len = sizeof(sipx);
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
if (s < 0)
{
perror("IPX: socket: ");
exit(-1);
}
@@ -26,13 +20,13 @@ int main(int argc, char **argv)
sipx.sipx_port = 0;
sipx.sipx_type = 17;
rc = bind(s, (struct sockaddr *)&sipx, sizeof(sipx));
if (rc < 0) {
rc = bind(s, (struct sockaddr *) &sipx, sizeof(sipx));
if (rc < 0)
{
perror("IPX: bind: ");
exit(-1);
}
rc = getsockname(s, (struct sockaddr *)&sipx, &len);
rc = getsockname(s, (struct sockaddr *) &sipx, &len);
sipx.sipx_port = htons(0x5000);
sipx.sipx_node[0] = 0xFF;
sipx.sipx_node[1] = 0xFF;
@@ -42,7 +36,7 @@ int main(int argc, char **argv)
sipx.sipx_node[5] = 0xFF;
rc = sendto(s, msg, strlen(msg), 0, (struct sockaddr *)&sipx,
sizeof(sipx));
sizeof(sipx));
if (rc < 0) {
perror("IPX: send: ");
exit(-1);

View File

@@ -1,31 +1,24 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netipx/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include "samples.h"
struct rip_data {
struct rip_data
{
uint32_t rip_net;
uint16_t rip_hops;
uint16_t rip_ticks;
} __attribute__ ((packed));
int
main(int argc, char **argv)
int main(int argc, char **argv)
{
struct sockaddr_ipx sipx;
int result;
int s;
char msg[1024];
int len;
char *bptr;
struct rip_data *rp;
struct sockaddr_ipx sipx;
int result;
int s;
char msg[1024];
char *bptr;
struct rip_data *rp;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
if (s < 0)
{
perror("IPX: socket: ");
exit(-1);
}
@@ -33,33 +26,43 @@ main(int argc, char **argv)
sipx.sipx_network = 0;
sipx.sipx_port = htons(0x453);
sipx.sipx_type = 17;
result = bind(s, (struct sockaddr *)&sipx, sizeof(sipx));
if (result < 0) {
result = bind(s, (struct sockaddr *) &sipx, sizeof(sipx));
if (result < 0)
{
perror("IPX: bind: ");
exit(-1);
}
while (1)
{
socklen_t len;
size_t rclen;
while (1) {
len = sizeof(sipx);
result = recvfrom(s, msg, sizeof(msg), 0,
(struct sockaddr *)&sipx, &len);
if (result < 0) {
result = recvfrom(s, msg, sizeof(msg), 0,
(struct sockaddr *) &sipx, &len);
if (result < 0)
{
perror("IPX: recvfrom");
exit(-1);
}
if (result < 2) {
fprintf(stderr, "Received packet is too short to be RIP packet (%d bytes)\n", result);
continue;
}
rclen = result - 2;
bptr = msg;
result -= 2;
printf("RIP packet from: %08X:%02X%02X%02X%02X%02X%02X\n",
htonl(sipx.sipx_network),
sipx.sipx_node[0], sipx.sipx_node[1],
sipx.sipx_node[2], sipx.sipx_node[3],
sipx.sipx_node[6], sipx.sipx_node[5]);
(u_int32_t)htonl(sipx.sipx_network),
sipx.sipx_node[0], sipx.sipx_node[1],
sipx.sipx_node[2], sipx.sipx_node[3],
sipx.sipx_node[6], sipx.sipx_node[5]);
bptr += 2;
rp = (struct rip_data *) bptr;
while (result >= sizeof(struct rip_data)) {
printf("\tNET: %08X HOPS: %d\n", ntohl(rp->rip_net),
ntohs(rp->rip_hops));
result -= sizeof(struct rip_data);
while (rclen >= sizeof(struct rip_data))
{
printf("\tNET: %08X HOPS: %d\n", (u_int32_t)ntohl(rp->rip_net),
ntohs(rp->rip_hops));
rclen -= sizeof(struct rip_data);
rp++;
}
}

8
Samples/samples.h Normal file
View File

@@ -0,0 +1,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netipx/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>

View File

@@ -1,93 +1,94 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netipx/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include "samples.h"
struct sap_data {
uint16_t sap_type;
char sap_name[48];
uint32_t sap_net;
uint8_t sap_node[6];
uint16_t sap_sock;
uint16_t sap_hops;
struct sap_data
{
uint16_t sap_type;
char sap_name[48];
uint32_t sap_net;
uint8_t sap_node[6];
uint16_t sap_sock;
uint16_t sap_hops;
} __attribute__ ((packed));
int
main(int argc, char **argv)
int main(int argc, char **argv)
{
int s;
int result;
struct sockaddr_ipx sipx;
char msg[1024];
long val = 0;
int len;
char *bptr;
struct sap_data *sp;
int s;
int result;
struct sockaddr_ipx sipx;
char msg[1024];
long val = 0;
char *bptr;
struct sap_data *sp;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
if (s < 0)
{
perror("IPX: socket: ");
exit(-1);
}
result = setsockopt(s, SOL_SOCKET, SO_DEBUG, &val, 4);
if (result < 0) {
if (result < 0)
{
perror("IPX: setsockopt: ");
exit(-1);
}
sipx.sipx_family = PF_IPX;
sipx.sipx_network = 0L;
sipx.sipx_port = htons(0x452);
sipx.sipx_type = 17;
result = bind(s, (struct sockaddr *)&sipx, sizeof(sipx));
if (result < 0) {
result = bind(s, (struct sockaddr *) &sipx, sizeof(sipx));
if (result < 0)
{
perror("IPX: bind: ");
exit(-1);
}
while (1)
{
socklen_t len;
size_t rclen;
while (1) {
len = 1024;
result = recvfrom(s, msg, sizeof(msg), 0,
(struct sockaddr *)&sipx, &len);
if (result < 0) {
result = recvfrom(s, msg, sizeof(msg), 0,
(struct sockaddr *) &sipx, &len);
if (result < 0)
{
perror("IPX: recvfrom: ");
exit(-1);
}
if (result < 2) {
fprintf(stderr, "Received packet is too short to be SAP packet (%d bytes)\n", result);
continue;
}
rclen = result - 2;
bptr = msg;
result -= 2;
printf("SAP: OP is %x %x\n", bptr[0], bptr[1]);
printf("Length is %d\n", result);
printf("Length is %zu\n", rclen);
if (bptr[1] != 2)
continue;
bptr += 2;
sp = (struct sap_data *) bptr;
while (result >= sizeof(struct sap_data)) {
int i;
while (rclen >= sizeof(struct sap_data))
{
int i;
sp->sap_name[32] = '\0';
for (i = 31; (i > 0) && (sp->sap_name[i] == '_'); i--);
i++;
sp->sap_name[i] = '\0';
printf("NAME: %s TYPE: %x HOPS: %x\n", sp->sap_name,
ntohs(sp->sap_type), ntohs(sp->sap_hops));
ntohs(sp->sap_type), ntohs(sp->sap_hops));
printf("%x:%x %x %x %x %x %x: %x\n",
ntohl(sp->sap_net),
sp->sap_node[0],
sp->sap_node[1],
sp->sap_node[2],
sp->sap_node[3],
sp->sap_node[4],
sp->sap_node[5],
ntohs(sp->sap_sock));
result -= sizeof(struct sap_data);
(u_int32_t)ntohl(sp->sap_net),
sp->sap_node[0],
sp->sap_node[1],
sp->sap_node[2],
sp->sap_node[3],
sp->sap_node[4],
sp->sap_node[5],
ntohs(sp->sap_sock));
rclen -= sizeof(struct sap_data);
sp++;
}
}

73
config.h Normal file
View File

@@ -0,0 +1,73 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the 'bindtextdomain' function. */
#define HAVE_BINDTEXTDOMAIN 1
/* Define to 1 if you have the 'gettext' function. */
#define HAVE_GETTEXT 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <libintl.h> header file. */
#define HAVE_LIBINTL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the 'textdomain' function. */
#define HAVE_TEXTDOMAIN 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define location of message catalogs */
#define LOCALEDIR "/usr/share/locale"
/* Name of package */
#define PACKAGE "ipx-utils"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "pasis.ua@gmail.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "ipx-utils"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "ipx-utils 1.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ipx-utils"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.2"
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "1.2"

72
config.h.in Normal file
View File

@@ -0,0 +1,72 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the 'bindtextdomain' function. */
#undef HAVE_BINDTEXTDOMAIN
/* Define to 1 if you have the 'gettext' function. */
#undef HAVE_GETTEXT
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <libintl.h> header file. */
#undef HAVE_LIBINTL_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the 'textdomain' function. */
#undef HAVE_TEXTDOMAIN
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define location of message catalogs */
#undef LOCALEDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION

72
config.h.in~ Normal file
View File

@@ -0,0 +1,72 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the 'bindtextdomain' function. */
#undef HAVE_BINDTEXTDOMAIN
/* Define to 1 if you have the 'gettext' function. */
#undef HAVE_GETTEXT
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <libintl.h> header file. */
#undef HAVE_LIBINTL_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the 'textdomain' function. */
#undef HAVE_TEXTDOMAIN
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define location of message catalogs */
#undef LOCALEDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION

View File

@@ -1,8 +1,29 @@
dnl Define a config.h string from a configure directory variable.
AC_DEFUN([AC_DEFINE_DIR], [
prefix_NONE=
exec_prefix_NONE=
test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix
test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix
ac_define_dir=`eval echo [$]$2`
ac_define_dir=`eval echo [$]ac_define_dir`
AC_DEFINE_UNQUOTED([$1], ["$ac_define_dir"], [$3])
test "$prefix_NONE" && prefix=NONE
test "$exec_prefix_NONE" && exec_prefix=NONE
])
AC_INIT([ipx-utils], [1.2], [pasis.ua@gmail.com])
AM_INIT_AUTOMAKE([subdir-objects])
AC_CONFIG_SRCDIR([src/ipx_configure.c])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile])
AC_CHECK_HEADERS([libintl.h])
AC_SEARCH_LIBS([gettext], [intl])
AC_CHECK_FUNCS([gettext bindtextdomain textdomain])
AC_DEFINE_DIR([LOCALEDIR], [localedir], [Define location of message catalogs])
AC_PROG_CC
AM_PROG_CC_C_O

7195
configure~ Executable file

File diff suppressed because it is too large Load Diff

45
docs/ipx_cmd.8 Normal file
View File

@@ -0,0 +1,45 @@
.TH IPX_CMD 8 "IPX Utilities" "ipx_cmd"
.SH NAME
ipx_cmd \- bridge between Novell's SCMD driver and local IPX network
.SH SYNOPSIS
.B ipx_cmd
\fB\-A\fP \fIserver name\fP
[ \fB\-l\fP \fIlocal interface name\fP ]
.SH DESCRIPTION
.B ipx_cmd
moves packets from \fItap\fP\fBN\fP to \fIserver\fP and vice versa.
It is something like \fBIPX Tunnel\fP, but it uses Novell Netware 5
server \fBCompatibility Mode Driver\fP (AKA \fBMigration Agent\fP) on the
other end of wire. You must first configure your kernel \fItap\fP\fBN\fP
device with IPX \fBEthernetII\fP frame and with network number set up on
server (you can use kernel autodetection).
.SH OPTIONS
.TP
\fB\-A\fP \fIserver name\fP
This is IP name of compatibility mode server. You can use DNS name or dotted
quad to specify server address.
.TP
\fB\-l\fP \fIlocal interface name\fP
This allows you to specify, which of your IP addresses should be used as
IP address of client side of CMD driver. You must configure your \fItap\fP\fBN\fP
device with hardware address \fB7E:01:AA:BB:CC:DD\fP, where AA:BB:CC:DD is
your IP address in hexa.
.SH EXAMPLE
If you are on server \fIplatan.vc.cvut.cz\fP (\fI147.32.240.81\fP) and your
migration agent runs on server \fIboris.vc.cvut.cz\fP, you can configure
your system with:
.RS 3
insmod ethertap
.br
ifconfig tap0 hw ether 7E:01:93:20:F0:51 up
.br
ipx_interface add -p tap0 EtherII
.br
ipx_cmd -A boris.vc.cvut.cz -l 147.32.240.81 &
.RE
.SH BUGS
This program was written to satisfy my own needs and should be really improved.
At least it should configure \fItap\fP interface itself.
.SH AUTHOR
Petr Vandrovec <vandrove@vc.cvut.cz>

BIN
ipx_cmd Executable file

Binary file not shown.

BIN
ipxdump Executable file

Binary file not shown.

BIN
ipxparse Executable file

Binary file not shown.

423
src/ipx_cmd.c Normal file
View File

@@ -0,0 +1,423 @@
/*
ipx_cmd.c - IPX Compatibility mode tunnel
Copyright (C) 1999 Petr Vandrovec
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Revision history:
0.00 1999 Petr Vandrovec <vandrove@vc.cvut.cz>
Initial revision.
1.00 1999, November 20 Petr Vandrovec <vandrove@vc.cvut.cz>
Added license.
1.01 2001, June 16 Petr Vandrovec <vandrove@vc.cvut.cz>
Cleanup some compilation warnings.
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <ncp/ext/socket.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <net/if_arp.h> /* TODO: linux/if_arp.h */
#include <ncp/kernel/ipx.h>
#include <ncp/kernel/if.h>
#include <ncp/kernel/types.h>
#include "netlink.h"
#include "nls.h"
#define _(X) gettext(X)
#define NOVELL_SCMD_PORT (2645)
/* Move them to configure... */
#ifndef AF_NETLINK
#define AF_NETLINK 16
#endif
#ifndef PF_NETLINK
#define PF_NETLINK AF_NETLINK
#endif
/* we are doing EthernetII... Any objections? */
struct {
u_int16_t unknown __attribute__((packed));
u_int8_t dst[6];
u_int8_t src[6];
u_int16_t type __attribute__((packed));
u_int8_t ipx[16384];
} __attribute__((packed)) buffer;
static int getiflist(int fd, struct ifconf* ifc) {
int i;
for (i = 0; i < 32; i++) {
int err;
ifc->ifc_len = 65536; /* ignored */
ifc->ifc_req = NULL;
err = ioctl(fd, SIOCGIFCONF, ifc);
if (err < 0)
continue;
if (!ifc->ifc_len)
return 0;
ifc->ifc_req = (struct ifreq*)malloc(ifc->ifc_len);
err = ioctl(fd, SIOCGIFCONF, ifc);
if (!err)
return 0;
free(ifc->ifc_buf);
}
ifc->ifc_len = 0;
ifc->ifc_req = NULL;
return errno;
}
static char* progname;
static int findtap(int fd_ipx, u_int32_t local) {
int i;
u_int8_t localhw[6];
localhw[0] = 0x7E;
localhw[1] = 0x01;
memcpy(localhw+2, &local, 4);
for (i = 0; i < 16; i++) {
struct ifreq ifr;
int err;
sprintf(ifr.ifr_name, "tap%d", i);
((struct sockaddr_ipx*)&ifr.ifr_addr)->sipx_type = IPX_FRAME_ETHERII;
err = ioctl(fd_ipx, SIOCGIFHWADDR, &ifr);
if (err >= 0) {
if ((ifr.ifr_addr.sa_family == ARPHRD_ETHER) && !memcmp(ifr.ifr_addr.sa_data, localhw, 6)) {
err = ioctl(fd_ipx, SIOCGIFADDR, &ifr);
if (err >= 0) {
if (!memcmp(((struct sockaddr_ipx*)&ifr.ifr_addr)->sipx_node, localhw, 6)) {
return i;
}
}
}
}
}
return -EADDRNOTAVAIL;
}
static void usage(void) {
fprintf(stderr, _("usage: %s -A migration_agent [-l local_ip]\n"), progname);
return;
}
int main(int argc, char* argv[]) {
int fd_ip;
struct sockaddr_in localIP;
int status;
int fd_netlink;
struct sockaddr_nl localNET;
int arg;
int maxfd;
fd_set rcvset;
int opt;
char *server = NULL;
struct hostent* hent;
u_int32_t serveraddr;
u_int32_t local = htonl(INADDR_ANY);
int local_ok;
struct ifconf ifc;
struct ifreq* curr;
struct ifreq* stop;
int tapnum;
int fd_ipx;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
{
char* i;
i = strrchr(argv[0], '/');
progname = i?i+1:argv[0];
}
while ((opt = getopt(argc, argv, "A:l:")) != -1) {
switch (opt) {
case 'A':
server = optarg;
break;
case 'l':
{
hent = gethostbyname(optarg);
if (!hent) {
fprintf(stderr, _("%s: %s: "),
progname,
optarg);
herror("");
exit(99);
}
if (hent->h_addrtype != AF_INET) {
fprintf(stderr, _("%s: Address of %s is not IP\n"),
progname,
optarg);
exit(99);
}
if (hent->h_length != 4) {
fprintf(stderr, _("%s: Address of %s is not 4 bytes long\n"),
progname,
optarg);
exit(99);
}
memcpy(&local, hent->h_addr, 4);
}
break;
default:
usage();
exit(99);
}
}
if (!server) {
usage();
exit(99);
}
hent = gethostbyname(server);
if (!hent) {
fprintf(stderr, _("%s: %s: "),
progname,
server);
herror("");
exit(99);
}
if (hent->h_addrtype != AF_INET) {
fprintf(stderr, _("%s: Address of %s is not IP\n"),
progname,
server);
exit(99);
}
if (hent->h_length != 4) {
fprintf(stderr, _("%s: Address of %s is not 4 bytes long\n"),
progname,
server);
exit(99);
}
memcpy(&serveraddr, hent->h_addr, 4);
fd_ip = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd_ip == -1) {
int err = errno;
fprintf(stderr, _("%s: Cannot create UDP/IP socket: %s\n"),
progname,
strerror(err));
return 1;
}
status = getiflist(fd_ip, &ifc);
if (status) {
close(fd_ip);
fprintf(stderr, _("%s: Cannot get list of local interfaces: %s\n"),
progname,
strerror(status));
return 1;
}
curr = ifc.ifc_req;
stop = (struct ifreq*)(((u_int8_t*)curr) + ifc.ifc_len);
local_ok = 0;
while (curr < stop) {
if (curr->ifr_addr.sa_family == AF_INET) {
u_int32_t net = ((struct sockaddr_in*)&curr->ifr_addr)->sin_addr.s_addr;
if (((ntohl(net) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET) {
if (local == htonl(INADDR_ANY))
local = net;
if (local == net)
local_ok = 1;
}
}
curr++;
}
free(ifc.ifc_req);
if (!local_ok) {
close(fd_ip);
fprintf(stderr, _("%s: Cannot find local requested address\n"),
progname);
return 1;
}
/* TBD: enable SO_REUSEADDR? */
localIP.sin_family = AF_INET;
localIP.sin_addr.s_addr = htonl(INADDR_ANY);
localIP.sin_port = htons(NOVELL_SCMD_PORT);
status = bind(fd_ip, (struct sockaddr*)&localIP, sizeof(localIP));
if (status) {
int err = errno;
close(fd_ip);
fprintf(stderr, _("%s: Cannot bind requested address to IP socket: %s\n"),
progname,
strerror(err));
return 1;
}
/* OK, we have local IP address... Now find appropriate tap device */
fd_ipx = socket(PF_IPX, SOCK_DGRAM, IPXPROTO_IPX);
if (fd_ipx < 0) {
int err = errno;
close(fd_ip);
fprintf(stderr, _("%s: Cannot create IPX socket: %s\n"),
progname,
strerror(err));
return 1;
}
tapnum = findtap(fd_ipx, local);
if (tapnum < 0) {
close(fd_ipx);
close(fd_ip);
fprintf(stderr, _("%s: Cannot find ethertap interface: %s\n"),
progname,
strerror(-tapnum));
return 1;
}
close(fd_ipx);
fd_netlink = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_TAPBASE+tapnum);
if (fd_netlink == -1) {
int err = errno;
close(fd_ip);
fprintf(stderr, _("%s: Cannot create NETLINK socket: %s\n"),
progname,
strerror(err));
return 1;
}
localNET.nl_family = AF_NETLINK;
localNET.nl_pid = serveraddr;
localNET.nl_groups = ~0;
status = bind(fd_netlink, (struct sockaddr*)&localNET, sizeof(localNET));
if (status) {
int err = errno;
close(fd_netlink);
close(fd_ip);
fprintf(stderr, _("%s: Cannot bind requested address to NETLINK socket: %s\n"),
progname,
strerror(err));
return 1;
}
arg = fcntl(fd_ip, F_GETFL);
fcntl(fd_ip, F_SETFL, arg | O_NONBLOCK);
arg = fcntl(fd_netlink, F_GETFL);
fcntl(fd_netlink, F_SETFL, arg | O_NONBLOCK);
maxfd = fd_ip;
if (fd_netlink > maxfd)
maxfd = fd_netlink;
FD_ZERO(&rcvset);
printf("Running...\n");
while (1) {
FD_SET(fd_ip, &rcvset);
FD_SET(fd_netlink, &rcvset);
status = select(maxfd+1, &rcvset, NULL, NULL, NULL);
if (status > 0) {
if (FD_ISSET(fd_ip, &rcvset)) {
struct sockaddr_in remoteIP;
socklen_t remoteIPlen = sizeof(remoteIP);
status = recvfrom(fd_ip, buffer.ipx, sizeof(buffer.ipx), 0, (struct sockaddr*)&remoteIP, &remoteIPlen);
if (status > 0) {
if (remoteIP.sin_port != htons(NOVELL_SCMD_PORT)) {
/* invalid source port... faked? */
} else if (remoteIP.sin_addr.s_addr != serveraddr) {
/* invalid server... faked? */
} else if (status < 2 + 2 + 1 + 1 + 12 + 12) {
/* too short... */
} else {
int ipxLen = ntohs(*(u_int16_t*)(buffer.ipx+2));
if (ipxLen > status) {
/* too big... */
} else {
/* looks OK... */
status += 2 + 6 + 6 + 2;
buffer.unknown = 0;
buffer.type = htons(0x8137);
buffer.src[0] = 0x7E;
buffer.src[1] = 0x01;
memcpy(buffer.src+2, &remoteIP.sin_addr.s_addr, 4);
buffer.dst[0] = 0x7E;
buffer.dst[1] = 0x01;
memcpy(buffer.dst+2, &local, 4);
{
struct sockaddr_nl remoteNETLINK;
int e;
remoteNETLINK.nl_family = AF_NETLINK;
remoteNETLINK.nl_pid = 0;
remoteNETLINK.nl_groups = 0;
e = sendto(fd_netlink, &buffer, status, 0, (struct sockaddr*)&remoteNETLINK, sizeof(remoteNETLINK));
if (e < 0)
sendto(fd_netlink, &buffer, status, 0, (struct sockaddr*)&remoteNETLINK, sizeof(remoteNETLINK));
}
}
}
}
}
if (FD_ISSET(fd_netlink, &rcvset)) {
struct sockaddr_in remoteNETLINK;
socklen_t remoteNETLINKlen = sizeof(remoteNETLINK);
status = recvfrom(fd_netlink, &buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteNETLINK, &remoteNETLINKlen);
if (status > 0) {
if (status < 2 + 6 + 6 + 2 + 2 + 2 + 1 + 1 + 12 + 12) {
/* too short... faked? */
} else if (buffer.type != htons(0x8137)) {
/* invalid frame */
} else {
int ipxLen = ntohs(*(u_int16_t*)(buffer.ipx+2));
status -= 2 + 6 + 6 + 2;
if (ipxLen > status) {
/* too big... */
} else {
/* looks OK... */
{
struct sockaddr_in remoteIP;
int e;
remoteIP.sin_family = AF_INET;
remoteIP.sin_addr.s_addr = serveraddr;
remoteIP.sin_port = htons(NOVELL_SCMD_PORT);
e = sendto(fd_ip, buffer.ipx, status, 0, (struct sockaddr*)&remoteIP, sizeof(remoteIP));
if (e < 0)
sendto(fd_ip, buffer.ipx, status, 0, (struct sockaddr*)&remoteIP, sizeof(remoteIP));
}
}
}
}
}
}
}
close(fd_netlink);
close(fd_ip);
return 0;
}

View File

@@ -1,131 +1,168 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <getopt.h> /* must be before stdio/unistd, otherwise multiple declaration warning is shown */
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <getopt.h>
#include <stdlib.h>
#include <strings.h>
#include <netipx/ipx.h>
#include <string.h>
#include <ncp/kernel/ipx.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include "nls.h"
struct option options[] = {
{ "auto_primary", required_argument, NULL, 1 },
{ "auto_interface", required_argument, NULL, 2 },
{ "help", no_argument, NULL, 3},
{ NULL, 0, NULL, 0 }
struct option options[] =
{
{ "auto_primary", required_argument, NULL, 'p'},
{ "auto-primary", required_argument, NULL, 'p'},
{ "auto_interface", required_argument, NULL, 'i'},
{ "auto-interface", required_argument, NULL, 'i'},
{ "help", no_argument, NULL, 'h'},
{ NULL, 0, NULL, 0}
};
char *progname;
static char *progname;
void
static void
usage(void)
{
fprintf(stderr,
"Usage: %s --auto_primary=[on|off]\n\
Usage: %s --auto_interface=[on|off]\n\
Usage: %s --help\n\
Usage: %s\n", progname, progname, progname, progname);
fprintf(stderr,
_("Usage: %s --auto_primary=[on|off]\n"
"Usage: %s --auto_interface=[on|off]\n"
"Usage: %s --help\n"
"Usage: %s\n"), progname, progname, progname, progname);
}
int
map_string_to_bool(char *optarg)
static int
map_string_to_bool(char *opt)
{
if ((strcasecmp(optarg, "ON") == 0) ||
(strcasecmp(optarg, "TRUE") == 0) ||
(strcasecmp(optarg, "SET") == 0) ||
(strcasecmp(optarg, "YES") == 0)) {
/* TODO: YES/NO VALUE FROM LIBC */
if ((strcasecmp(opt, "ON") == 0) ||
(strcasecmp(opt, "TRUE") == 0) ||
(strcasecmp(opt, "SET") == 0) ||
(strcasecmp(opt, "YES") == 0) ||
(strcasecmp(opt, "1") == 0))
{
return 1;
} else if ((strcasecmp(optarg, "OFF") == 0) ||
(strcasecmp(optarg, "FALSE") == 0) ||
(strcasecmp(optarg, "CLEAR") == 0) ||
(strcasecmp(optarg, "NO") == 0)) {
} else if ((strcasecmp(opt, "OFF") == 0) ||
(strcasecmp(opt, "FALSE") == 0) ||
(strcasecmp(opt, "CLEAR") == 0) ||
(strcasecmp(opt, "NO") == 0) ||
(strcasecmp(opt, "0") == 0))
{
return 0;
}
}
return -1;
}
int
main(int argc, char **argv)
{
int s;
int result;
char errmsg[80];
char val;
int option_index = 0;
int got_auto_pri = 0;
int got_auto_itf = 0;
ipx_config_data data;
int s;
int result;
int val;
int got_auto_pri = 0;
int got_auto_itf = 0;
ipx_config_data data;
progname = argv[0];
setlocale(LC_ALL, "");
#if defined(HAVE_BINDTEXTDOMAIN) && defined(HAVE_TEXTDOMAIN)
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
#endif
progname = argv[0];
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
if (s < 0)
{
int old_errno = errno;
fprintf(stderr, _("%s: socket: %s\n"), progname, strerror(errno));
if (old_errno == -EINVAL)
{
fprintf(stderr, _("Probably you have no IPX support in "
"your kernel\n"));
}
exit(-1);
}
sprintf(errmsg, "%s: ioctl", progname);
while ((result = getopt_long(argc, argv, "", options,
&option_index)) != -1) {
switch (result) {
case 1:
while ((result = getopt_long(argc, argv, "hi:p:", options,
NULL)) != -1)
{
switch (result)
{
case 'p':
if (got_auto_pri)
break;
got_auto_pri++;
val = map_string_to_bool(optarg);
if (val < 0) {
if (val < 0)
{
usage();
exit(-1);
}
{
unsigned char v = val;
result = ioctl(s, SIOCAIPXPRISLT, &val);
if (result < 0) {
perror(errmsg);
result = ioctl(s, SIOCAIPXPRISLT, &v);
}
if (result < 0)
{
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
exit(-1);
}
break;
case 2:
if (got_auto_itf)
case 'i':
if (got_auto_itf)
break;
got_auto_itf++;
val = map_string_to_bool(optarg);
if (val < 0) {
if (val < 0)
{
usage();
exit(-1);
}
{
unsigned char v = val;
result = ioctl(s, SIOCAIPXITFCRT, &val);
if (result < 0) {
perror(errmsg);
result = ioctl(s, SIOCAIPXITFCRT, &v);
}
if (result < 0)
{
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
exit(-1);
}
break;
case 3:
case 'h':
usage();
break;
}
}
result = ioctl(s, SIOCIPXCFGDATA, &data);
if (result < 0) {
perror(errmsg);
exit(-1);
if (result < 0)
{
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
return -1;
}
if (argc == 1) {
fprintf(stdout, "Auto Primary Select is %s\n\
Auto Interface Create is %s\n",
(data.ipxcfg_auto_select_primary) ? "ON" : "OFF",
(data.ipxcfg_auto_create_interfaces) ? "ON" : "OFF");
if (argc == 1)
{
fprintf(stdout, _("Auto Primary Select is %s\n"
"Auto Interface Create is %s\n"),
(data.ipxcfg_auto_select_primary) ? _("ON") : _("OFF"),
(data.ipxcfg_auto_create_interfaces) ? _("ON") : _("OFF"));
}
exit(0);
return 0;
}

View File

@@ -1,5 +1,6 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
@@ -10,389 +11,452 @@
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netipx/ipx.h>
#include <linux/if.h>
#include <ncp/kernel/ipx.h>
#include <ncp/kernel/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
static struct ifreq id;
static char *progname;
#include "ipxutil.h"
void
#include "nls.h"
static struct ifreq id;
static char *progname;
static void
usage(void)
{
fprintf(stderr, "Usage: %s add [-p] device frame_type [net_number]\n\
Usage: %s del device frame_type\n\
Usage: %s delall\n\
Usage: %s check device frame_type\n", progname, progname, progname, progname);
exit(-1);
fprintf(stderr,
_("Usage: %s add [-p] device frame_type [net_number[:node]]\n"
"Usage: %s del device frame_type\n"
"Usage: %s delall\n"
"Usage: %s check device frame_type\n"),
progname, progname, progname, progname);
}
struct frame_type {
char *ft_name;
unsigned char ft_val;
} frame_types[] = {
{"802.2", IPX_FRAME_8022},
struct frame_type
{
const char *ft_name;
unsigned char ft_val;
}
frame_types[] =
{
{
"802.2", IPX_FRAME_8022
}
,
#ifdef IPX_FRAME_TR_8022
{"802.2TR", IPX_FRAME_TR_8022},
{
"802.2TR", IPX_FRAME_TR_8022
}
,
#endif
{"802.3", IPX_FRAME_8023},
{"SNAP", IPX_FRAME_SNAP},
{"EtherII", IPX_FRAME_ETHERII}
{
"802.3", IPX_FRAME_8023
}
,
{
"SNAP", IPX_FRAME_SNAP
}
,
{
"EtherII", IPX_FRAME_ETHERII
}
};
#define NFTYPES (sizeof(frame_types)/sizeof(struct frame_type))
int
static int
lookup_frame_type(char *frame)
{
size_t j;
size_t j;
for (j = 0; (j < NFTYPES) &&
(strcasecmp(frame_types[j].ft_name, frame));
j++)
for (j = 0; (j < NFTYPES) &&
(strcasecmp(frame_types[j].ft_name, frame));
j++)
;
if (j != NFTYPES)
return j;
fprintf(stderr, "%s: Frame type must be", progname);
for (j = 0; j < NFTYPES; j++) {
fprintf(stderr, "%s%s",
(j == NFTYPES-1) ? " or " : " ",
fprintf(stderr, _("%s: Frame type must be"), progname);
for (j = 0; j < NFTYPES; j++)
{
fprintf(stderr, "%s%s",
(j == NFTYPES - 1) ? _(" or ") : " ",
frame_types[j].ft_name);
}
fprintf(stderr, ".\n");
return -1;
}
int
static int
ipx_add_interface(int argc, char **argv)
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
unsigned long netnum;
char errmsg[80];
int i, fti = 0;
int c;
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr;
int s;
int result;
int i, fti = 0;
int c;
sipx->sipx_special = IPX_SPECIAL_NONE;
sipx->sipx_network = 0L;
memset(sipx->sipx_node, 0, sizeof(sipx->sipx_node));
sipx->sipx_type = IPX_FRAME_NONE;
while ((c = getopt(argc, argv, "p")) > 0) {
switch (c) {
case 'p': sipx->sipx_special = IPX_PRIMARY; break;
while ((c = getopt(argc, argv, "p")) > 0)
{
switch (c)
{
case 'p':
sipx->sipx_special = IPX_PRIMARY;
break;
}
}
if (((i = (argc - optind)) < 2) || (i > 3)) {
if (((i = (argc - optind)) < 2) || (i > 3))
{
usage();
return -1;
}
for (i = optind; i < argc; i++) {
switch (i-optind) {
for (i = optind; i < argc; i++)
{
switch (i - optind)
{
case 0: /* Physical Device - Required */
strcpy(id.ifr_name, argv[i]);
break;
case 1: /* Frame Type - Required */
case 1: /* Frame Type - Required */
fti = lookup_frame_type(argv[i]);
if (fti < 0)
exit(-1);
if (fti < 0) {
return -1;
}
sipx->sipx_type = frame_types[fti].ft_val;
break;
case 2: /* Network Number - Optional */
netnum = strtoul(argv[i], (char **)NULL, 16);
if (netnum == 0xffffffffL) {
fprintf(stderr,
"%s: Inappropriate network number %08lX\n",
progname, netnum);
exit(-1);
case 2: /* Network Number - Optional */
sscanf_ipx_addr(sipx, argv[i], SSIPX_NETWORK | SSIPX_NODE);
if (sipx->sipx_network == htonl(0xffffffffL))
{
fprintf(stderr,
_("%s: Inappropriate network number %08lX\n"),
progname, (unsigned long)ntohl(sipx->sipx_network));
return -1;
}
sipx->sipx_network = htonl(netnum);
break;
}
}
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
}
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0)
{
int old_errno = errno;
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
if (old_errno == -EINVAL)
{
fprintf(stderr, _("Probably you have no IPX support in "
"your kernel\n"));
}
return -1;
}
i = 0;
sipx->sipx_family = AF_IPX;
sipx->sipx_action = IPX_CRTITF;
do {
do
{
result = ioctl(s, SIOCSIFADDR, &id);
i++;
} while ((i < 5) && (result < 0) && (errno == EAGAIN));
}
while ((i < 5) && (result < 0) && (errno == EAGAIN));
if (result == 0) exit(0);
switch (errno) {
if (result == 0) {
return 0;
}
switch (errno)
{
case EEXIST:
fprintf(stderr, "%s: Primary network already selected.\n",
fprintf(stderr, _("%s: Primary network already selected.\n"),
progname);
break;
case EADDRINUSE:
fprintf(stderr, "%s: Network number (%08X) already in use.\n",
progname, htonl(sipx->sipx_network));
fprintf(stderr, _("%s: Network number (%08X) already in use.\n"),
progname, (u_int32_t)htonl(sipx->sipx_network));
break;
case EPROTONOSUPPORT:
fprintf(stderr, "%s: Invalid frame type (%s).\n",
fprintf(stderr, _("%s: Invalid frame type (%s).\n"),
progname, frame_types[fti].ft_name);
break;
case ENODEV:
fprintf(stderr, "%s: No such device (%s).\n", progname,
fprintf(stderr, _("%s: No such device (%s).\n"), progname,
id.ifr_name);
break;
case ENETDOWN:
fprintf(stderr, "%s: Requested device (%s) is down.\n", progname,
fprintf(stderr, _("%s: Requested device (%s) is down.\n"), progname,
id.ifr_name);
break;
case EINVAL:
fprintf(stderr, "%s: Invalid device (%s).\n", progname,
fprintf(stderr, _("%s: Invalid device (%s).\n"), progname,
id.ifr_name);
break;
case EAGAIN:
fprintf(stderr,
"%s: Insufficient memory to create interface.\n",
fprintf(stderr,
_("%s: Insufficient memory to create interface.\n"),
progname);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
close(s);
return -1;
}
int
ipx_delall_interface(void)
static int
ipx_delall_interface(int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
char errmsg[80];
char buffer[80];
char device[20];
char frame_type[20];
int fti;
FILE *fp;
char *ret;
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr;
int s;
int result;
char buffer[80];
char device[20];
char frame_type[20];
int fti;
FILE *fp;
char *ret;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
return -1;
}
fp = fopen("/proc/net/ipx_interface", "r");
if (!fp) {
fp = fopen("/proc/net/ipx/interface", "r");
}
fp = fopen("/proc/net/ipx/interface", "r");
if (fp == NULL)
fp = fopen("/proc/net/ipx_interface", "r");
if (fp == NULL) {
{
close(s);
fprintf(stderr,
"%s: Unable to open \"/proc/net/ipx_interface.\"\n",
progname);
exit(-1);
_("%s: Unable to open \"%s.\"\n"),
progname,
"/proc/net/ipx_interface");
return -1;
}
ret = fgets(buffer, 80, fp);
if (ret == NULL) {
fprintf(stderr,
"%s: Unable to read \"/proc/net/ipx_interface.\"\n",
progname);
"%s: Unable to read \"/proc/net/ipx_interface.\"\n",
progname);
exit(-1);
}
while (fscanf(fp, "%s %s %s %s %s", buffer, buffer, buffer,
device, frame_type) == 5) {
device, frame_type) == 5)
{
sipx->sipx_network = 0L;
if (strcasecmp(device, "Internal") == 0) {
if (strcasecmp(device, "Internal") == 0)
{
sipx->sipx_special = IPX_INTERNAL;
} else {
} else
{
sipx->sipx_special = IPX_SPECIAL_NONE;
strcpy(id.ifr_name, device);
fti = lookup_frame_type(frame_type);
if (fti < 0) continue;
if (fti < 0)
continue;
sipx->sipx_type = frame_types[fti].ft_val;
}
sipx->sipx_action = IPX_DLTITF;
sipx->sipx_family = AF_IPX;
result = ioctl(s, SIOCSIFADDR, &id);
if (result == 0) continue;
switch (errno) {
if (result == 0)
continue;
switch (errno)
{
case EPROTONOSUPPORT:
fprintf(stderr, "%s: Invalid frame type (%s).\n",
fprintf(stderr, _("%s: Invalid frame type (%s).\n"),
progname, frame_type);
break;
case ENODEV:
fprintf(stderr, "%s: No such device (%s).\n",
fprintf(stderr, _("%s: No such device (%s).\n"),
progname, device);
break;
case EINVAL:
fprintf(stderr, "%s: No such IPX interface %s %s.\n",
fprintf(stderr, _("%s: No such IPX interface %s %s.\n"),
progname, device, frame_type);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
}
exit(0);
fclose(fp);
close(s);
return 0;
}
int
static int
ipx_del_interface(int argc, char **argv)
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
char errmsg[80];
int fti;
if (argc != 3) {
usage();
}
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr;
int s;
int result;
int fti;
if (argc != 2)
{
usage();
return -1;
}
sipx->sipx_network = 0L;
sipx->sipx_special = IPX_SPECIAL_NONE;
strcpy(id.ifr_name, argv[1]);
fti = lookup_frame_type(argv[2]);
if (fti < 0)
exit(-1);
strcpy(id.ifr_name, argv[0]);
fti = lookup_frame_type(argv[1]);
if (fti < 0) {
return -1;
}
sipx->sipx_type = frame_types[fti].ft_val;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
return -1;
}
sipx->sipx_action = IPX_DLTITF;
sipx->sipx_family = AF_IPX;
result = ioctl(s, SIOCSIFADDR, &id);
if (result == 0) exit(0);
if (result == 0) {
close(s);
return 0;
}
switch (errno) {
switch (errno)
{
case EPROTONOSUPPORT:
fprintf(stderr, "%s: Invalid frame type (%s).\n",
fprintf(stderr, _("%s: Invalid frame type (%s).\n"),
progname, frame_types[fti].ft_name);
break;
case ENODEV:
fprintf(stderr, "%s: No such device (%s).\n", progname,
fprintf(stderr, _("%s: No such device (%s).\n"), progname,
id.ifr_name);
break;
case EINVAL:
fprintf(stderr, "%s: No such IPX interface %s %s.\n", progname,
fprintf(stderr, _("%s: No such IPX interface %s %s.\n"), progname,
id.ifr_name, frame_types[fti].ft_name);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
close(s);
return -1;
}
int
static int
ipx_check_interface(int argc, char **argv)
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
char errmsg[80];
int fti;
if (argc != 3) {
usage();
}
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr;
int s;
int result;
int fti;
if (argc != 2)
{
usage();
return -1;
}
sipx->sipx_network = 0L;
strcpy(id.ifr_name, argv[1]);
fti = lookup_frame_type(argv[2]);
if (fti < 0)
exit(-1);
strcpy(id.ifr_name, argv[0]);
fti = lookup_frame_type(argv[1]);
if (fti < 0) {
return -1;
}
sipx->sipx_type = frame_types[fti].ft_val;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
return -1;
}
sipx->sipx_family = AF_IPX;
result = ioctl(s, SIOCGIFADDR, &id);
if (result == 0) {
if (result == 0)
{
close(s);
printf(
"IPX Address for (%s, %s) is %08X:%02X%02X%02X%02X%02X%02X.\n",
argv[1], frame_types[fti].ft_name,
htonl(sipx->sipx_network), sipx->sipx_node[0],
sipx->sipx_node[1], sipx->sipx_node[2],
sipx->sipx_node[3], sipx->sipx_node[4],
sipx->sipx_node[5]);
exit(0);
_("IPX Address for (%s, %s) is %08X:%02X%02X%02X%02X%02X%02X.\n"),
argv[1], frame_types[fti].ft_name,
(u_int32_t)htonl(sipx->sipx_network), sipx->sipx_node[0],
sipx->sipx_node[1], sipx->sipx_node[2],
sipx->sipx_node[3], sipx->sipx_node[4],
sipx->sipx_node[5]);
return 0;
}
switch (errno) {
switch (errno)
{
case EPROTONOSUPPORT:
fprintf(stderr, "%s: Invalid frame type (%s).\n",
fprintf(stderr, _("%s: Invalid frame type (%s).\n"),
progname, frame_types[fti].ft_name);
break;
case ENODEV:
fprintf(stderr, "%s: No such device (%s).\n", progname,
fprintf(stderr, _("%s: No such device (%s).\n"), progname,
id.ifr_name);
break;
case EADDRNOTAVAIL:
fprintf(stderr, "%s: No such IPX interface %s %s.\n", progname,
fprintf(stderr, _("%s: No such IPX interface %s %s.\n"), progname,
id.ifr_name, frame_types[fti].ft_name);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
close(s);
return -1;
}
int
main(int argc, char **argv)
int main(int argc, char **argv)
{
int i;
int i;
progname = argv[0];
if (argc < 2) {
usage();
exit(-1);
}
if (strncasecmp(argv[1], "add", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_add_interface(argc-1, argv);
} else if (strncasecmp(argv[1], "delall", 6) == 0) {
if (argc > 2) {
usage();
exit(-1);
}
ipx_delall_interface();
} else if (strncasecmp(argv[1], "del", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_del_interface(argc-1, argv);
} else if (strncasecmp(argv[1], "check", 5) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_check_interface(argc-1, argv);
}
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
if (argc < 2)
{
usage();
return -1;
}
if (strcasecmp(argv[1], "add") == 0)
{
for (i = 1; i < (argc - 1); i++)
argv[i] = argv[i + 1];
return ipx_add_interface(argc - 1, argv);
} else if (strcasecmp(argv[1], "delall") == 0)
{
return ipx_delall_interface(argc - 2, argv + 2);
} else if (strcasecmp(argv[1], "del") == 0)
{
return ipx_del_interface(argc - 2, argv + 2);
} else if (strcasecmp(argv[1], "check") == 0)
{
return ipx_check_interface(argc - 2, argv + 2);
}
usage();
return 0;
return -1;
}

View File

@@ -1,5 +1,5 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
@@ -9,193 +9,176 @@
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netipx/ipx.h>
#include <linux/if.h>
#include <ncp/kernel/ipx.h>
#include <ncp/kernel/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
static struct ifreq id;
static char *progname;
#include "ipxutil.h"
void
#include "nls.h"
static struct ifreq id;
static char *progname;
static void
usage(void)
{
fprintf(stderr, "Usage: %s add net_number(hex) node(hex)\n\
Usage: %s del\n", progname, progname);
exit(-1);
fprintf(stderr, _("Usage: %s add net_number(hex) node(hex)\n"
"Usage: %s del\n"),
progname, progname);
}
int
map_char_to_val(char dig)
{
char digit = tolower(dig);
if ((digit >= '0') && (digit <= '9')) {
return digit - '0';
} else if ((digit >= 'a') && (digit <= 'f')) {
return (10 + (digit - 'a'));
} else {
return 0;
}
}
int
static int
ipx_add_internal_net(int argc, char **argv)
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
unsigned long netnum;
char errmsg[80];
int nodelen;
char *node;
char tmpnode[13];
unsigned char *tout;
char *tin;
int i;
if (argc != 3) {
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr;
int s;
int result;
unsigned long netnum;
int i;
if (argc < 1)
{
usage();
return -1;
}
netnum = strtoul(argv[1], (char **)NULL, 16);
if ((netnum == 0L) || (netnum == 0xffffffffL)) {
fprintf(stderr, "%s: Inappropriate network number %08lX\n",
i = sscanf_ipx_addr(sipx, argv[0], SSIPX_NETWORK|SSIPX_NODE);
if (!(i & SSIPX_NETWORK)) {
fprintf(stderr, _("%s: Invalid internal network address %s\n"),
progname, argv[0]);
return -1;
}
if (!(i & SSIPX_NODE)) {
if (argc < 2)
memcpy(sipx->sipx_node, "\0\0\0\0\0\1", IPX_NODE_LEN);
else if (sscanf_ipx_addr(sipx, argv[1], SSIPX_NODE) != SSIPX_NODE) {
fprintf(stderr, _("%s: Invalid internal network node %s\n"),
progname, argv[1]);
return -1;
}
}
netnum = ntohl(sipx->sipx_network);
if ((netnum == 0L) || (netnum == 0xffffffffL))
{
fprintf(stderr, _("%s: Inappropriate network number %08lX\n"),
progname, netnum);
exit(-1);
return -1;
}
node = argv[2];
nodelen = strlen(node);
if (nodelen > 12) {
fprintf(stderr, "%s: Node length is too long (> 12).\n", progname);
exit(-1);
}
for (i = 0; (i < nodelen) && isxdigit(node[i]); i++)
;
if (i < nodelen) {
fprintf(stderr, "%s: Invalid value in node, must be hex digits.\n",
progname);
exit(-1);
}
strcpy(tmpnode, "000000000000");
memcpy(&(tmpnode[12-nodelen]), node, nodelen);
for (tin = tmpnode, tout = sipx->sipx_node; *tin != '\0'; tin += 2, tout++) {
*tout = (unsigned char) map_char_to_val(*tin);
*tout <<= 4;
*tout |= (unsigned char) map_char_to_val(*(tin+1));
}
if ((memcmp(sipx->sipx_node, "\0\0\0\0\0\0\0\0", IPX_NODE_LEN) == 0) ||
(memcmp(sipx->sipx_node, "\377\377\377\377\377\377", IPX_NODE_LEN) == 0)){
fprintf(stderr, "%s: Node is invalid.\n", progname);
exit(-1);
(memcmp(sipx->sipx_node, "\377\377\377\377\377\377", IPX_NODE_LEN) == 0))
{
fprintf(stderr, _("%s: Node is invalid.\n"), progname);
return -1;
}
sipx->sipx_network = htonl(netnum);
sipx->sipx_type = IPX_FRAME_NONE;
sipx->sipx_special = IPX_INTERNAL;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
return -1;
}
sipx->sipx_family = AF_IPX;
sipx->sipx_action = IPX_CRTITF;
i = 0;
do {
do
{
result = ioctl(s, SIOCSIFADDR, &id);
i++;
} while ((i < 5) && (result < 0) && (errno == EAGAIN));
}
while ((i < 5) && (result < 0) && (errno == EAGAIN));
if (result == 0) exit(0);
switch (errno) {
if (result == 0) {
return 0;
}
switch (errno)
{
case EEXIST:
fprintf(stderr, "%s: Primary network already selected.\n",
fprintf(stderr, _("%s: Primary network already selected.\n"),
progname);
break;
case EADDRINUSE:
fprintf(stderr, "%s: Network number (%08X) already in use.\n",
progname, htonl(sipx->sipx_network));
fprintf(stderr, _("%s: Network number (%08X) already in use.\n"),
progname, (u_int32_t)htonl(sipx->sipx_network));
break;
case EAGAIN:
fprintf(stderr,
"%s: Insufficient memory to create internal net.\n",
fprintf(stderr,
_("%s: Insufficient memory to create internal net.\n"),
progname);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
return -1;
}
int
ipx_del_internal_net(int argc, char **argv)
static int
ipx_del_internal_net(int argc, char **argv __attribute__((unused)))
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
char errmsg[80];
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr;
int s;
int result;
(void)argv;
if (argc != 1) {
if (argc != 0)
{
usage();
return -1;
}
sipx->sipx_network = 0L;
sipx->sipx_special = IPX_INTERNAL;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
return -1;
}
sipx->sipx_family = AF_IPX;
sipx->sipx_action = IPX_DLTITF;
result = ioctl(s, SIOCSIFADDR, &id);
if (result == 0) exit(0);
if (result == 0) {
return 0;
}
switch (errno) {
switch (errno)
{
case ENOENT:
fprintf(stderr, "%s: No internal network configured.\n", progname);
fprintf(stderr, _("%s: No internal network configured.\n"), progname);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
return -1;
}
int
main(int argc, char **argv)
{
int i;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
progname = argv[0];
if (argc < 2) {
if (argc < 2)
{
usage();
exit(-1);
return -1;
}
if (strncasecmp(argv[1], "add", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_add_internal_net(argc-1, argv);
} else if (strncasecmp(argv[1], "del", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_del_internal_net(argc-1, argv);
if (strcasecmp(argv[1], "add") == 0)
{
return ipx_add_internal_net(argc - 2, argv + 2);
} else if (strcasecmp(argv[1], "del") == 0)
{
return ipx_del_internal_net(argc - 2, argv + 2);
}
usage();
return 0;
return -1;
}

View File

@@ -1,5 +1,6 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
@@ -10,211 +11,209 @@
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netipx/ipx.h>
#include <ncp/kernel/ipx.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/route.h>
#include <ncp/kernel/route.h>
static struct rtentry rd;
static char *progname;
#include "ipxutil.h"
int
map_char_to_val(char dig)
{
char digit = tolower(dig);
if ((digit >= '0') && (digit <= '9')) {
return digit - '0';
} else if ((digit >= 'a') && (digit <= 'f')) {
return (10 + (digit - 'a'));
} else {
return 0;
}
}
#include "nls.h"
void
static struct rtentry rd;
static char *progname;
static void
usage(void)
{
fprintf(stderr,
"Usage: %s add network(hex) router_network(hex) router_node(hex)\n\
Usage: %s del network(hex)\n", progname, progname);
exit(-1);
fprintf(stderr,
_("Usage: %s add network(hex) router_network(hex) router_node(hex)\n"
"Usage: %s del network(hex)\n"),
progname, progname);
}
int
static int
ipx_add_route(int argc, char **argv)
{
/* Router */
struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway;
struct sockaddr_ipx *sr = (struct sockaddr_ipx *) &rd.rt_gateway;
/* Target */
struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst;
int s;
int result;
int nodelen;
int i;
unsigned long netnum;
char errmsg[80];
char *node;
char *tin;
char tmpnode[13];
unsigned char *tout;
if (argc != 4)
struct sockaddr_ipx *st = (struct sockaddr_ipx *) &rd.rt_dst;
int s;
int result;
int val;
int i;
if (argc < 2) {
usage();
return -1;
}
/* Network Number */
netnum = strtoul(argv[1], (char **)NULL, 16);
if ((netnum == 0xffffffffL) || (netnum == 0L)) {
fprintf(stderr, "%s: Inappropriate network number %08lX\n",
progname, netnum);
exit(-1);
if (sscanf_ipx_addr(st, argv[0], SSIPX_NETWORK) != SSIPX_NETWORK) {
fprintf(stderr, _("%s: Invalid network number %s\n"),
progname, argv[0]);
return -1;
}
if ((st->sipx_network == htonl(0xffffffffL)) ||
(st->sipx_network == htonl(0L)))
{
fprintf(stderr, _("%s: Inappropriate network number %08lX\n"),
progname, (unsigned long)ntohl(st->sipx_network));
return -1;
}
rd.rt_flags = RTF_GATEWAY;
st->sipx_network = htonl(netnum);
/* Router Network Number */
netnum = strtoul(argv[2], (char **)NULL, 16);
if ((netnum == 0xffffffffL) || (netnum == 0L)) {
fprintf(stderr, "%s: Inappropriate network number %08lX\n",
progname, netnum);
val = sscanf_ipx_addr(sr, argv[1], SSIPX_NETWORK|SSIPX_NODE);
if (!(val & SSIPX_NETWORK)) {
fprintf(stderr, _("%s: Invalid router address %s\n"),
progname, argv[1]);
return -1;
}
if (!(val & SSIPX_NODE)) {
if ((argc < 3) ||
(sscanf_ipx_addr(sr, argv[2], SSIPX_NODE) != SSIPX_NODE)) {
fprintf(stderr, _("%s: Invalid router node %s\n"),
progname, argv[2]);
return -1;
}
}
if ((sr->sipx_network == htonl(0xffffffffL)) ||
(sr->sipx_network == htonl(0L)))
{
fprintf(stderr, _("%s: Inappropriate network number %08lX\n"),
progname, (unsigned long)htonl(sr->sipx_network));
exit(-1);
}
sr->sipx_network = htonl(netnum);
/* Router Node */
node = argv[3];
nodelen = strlen(node);
if (nodelen > 12) {
fprintf(stderr, "%s: Node length is too long (> 12).\n",
progname);
exit(-1);
}
for (i = 0; (i < nodelen) && isxdigit(node[i]); i++)
;
if (i < nodelen) {
fprintf(stderr, "%s: Invalid value in node, must be hex digits.\n",
progname);
exit(-1);
}
strcpy(tmpnode, "000000000000");
memcpy(&(tmpnode[12-nodelen]), node, nodelen);
for (tin = tmpnode, tout = sr->sipx_node; *tin != '\0'; tin += 2, tout++) {
*tout = (unsigned char) map_char_to_val(*tin);
*tout <<= 4;
*tout |= (unsigned char) map_char_to_val(*(tin+1));
}
if ((memcmp(sr->sipx_node, "\0\0\0\0\0\0\0\0", IPX_NODE_LEN) == 0) ||
(memcmp(sr->sipx_node, "\377\377\377\377\377\377", IPX_NODE_LEN) == 0)){
fprintf(stderr, "%s: Node (%s) is invalid.\n", progname, tmpnode);
(memcmp(sr->sipx_node, "\377\377\377\377\377\377", IPX_NODE_LEN) == 0))
{
char tmpnode[IPX_NODE_LEN*2+1];
for (i = 0; i < IPX_NODE_LEN; i++)
sprintf(tmpnode+i*2, "%02X", sr->sipx_node[i]);
fprintf(stderr, _("%s: Node (%s) is invalid.\n"), progname, tmpnode);
exit(-1);
}
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
exit(-1);
}
sr->sipx_family = st->sipx_family = AF_IPX;
i = 0;
do {
do
{
result = ioctl(s, SIOCADDRT, &rd);
i++;
} while ((i < 5) && (result < 0) && (errno == EAGAIN));
}
while ((i < 5) && (result < 0) && (errno == EAGAIN));
if (result == 0) exit(0);
if (result == 0) {
return 0;
}
switch (errno) {
switch (errno)
{
case ENETUNREACH:
fprintf(stderr, "%s: Router network (%08X) not reachable.\n",
progname, htonl(sr->sipx_network));
fprintf(stderr, _("%s: Router network (%08X) not reachable.\n"),
progname, (u_int32_t)htonl(sr->sipx_network));
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
return -1;
}
int
static int
ipx_del_route(int argc, char **argv)
{
/* Router */
struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway;
struct sockaddr_ipx *sr = (struct sockaddr_ipx *) &rd.rt_gateway;
/* Target */
struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst;
int s;
int result;
unsigned long netnum;
char errmsg[80];
if (argc != 2) {
usage();
}
struct sockaddr_ipx *st = (struct sockaddr_ipx *) &rd.rt_dst;
int s;
int result;
unsigned long netnum;
if (argc != 1)
{
usage();
return -1;
}
rd.rt_flags = RTF_GATEWAY;
/* Network Number */
netnum = strtoul(argv[1], (char **)NULL, 16);
if ((netnum == 0xffffffffL) || (netnum == 0L)) {
fprintf(stderr, "%s: Inappropriate network number %08lX.\n",
progname, netnum);
exit(-1);
if (sscanf_ipx_addr(st, argv[0], SSIPX_NETWORK) != SSIPX_NETWORK) {
fprintf(stderr, _("%s: Invalid network number %s\n"),
progname, argv[0]);
return -1;
}
netnum = ntohl(st->sipx_network);
if ((netnum == 0xffffffffL) || (netnum == 0L))
{
fprintf(stderr, _("%s: Inappropriate network number %08lX.\n"),
progname, netnum);
return -1;
}
st->sipx_network = htonl(netnum);
st->sipx_family = sr->sipx_family = AF_IPX;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
if (s < 0)
{
fprintf(stderr, _("%s: socket: %s\n"), progname,
strerror(errno));
return -1;
}
result = ioctl(s, SIOCDELRT, &rd);
if (result == 0) exit(0);
if (result == 0) {
return 0;
}
switch (errno) {
switch (errno)
{
case ENOENT:
fprintf(stderr, "%s: Route not found for network %08lX.\n",
fprintf(stderr, _("%s: Route not found for network %08lX.\n"),
progname, netnum);
break;
case EPERM:
fprintf(stderr, "%s: Network %08lX is directly connected.\n",
fprintf(stderr, _("%s: Network %08lX is directly connected.\n"),
progname, netnum);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
fprintf(stderr, _("%s: ioctl: %s\n"), progname,
strerror(errno));
break;
}
exit(-1);
return -1;
}
int
main(int argc, char **argv)
{
int i;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
progname = argv[0];
if (argc < 2) {
if (argc < 2)
{
usage();
exit(-1);
return -1;
}
if (strncasecmp(argv[1], "add", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_add_route(argc-1, argv);
} else if (strncasecmp(argv[1], "del", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_del_route(argc-1, argv);
if (strcasecmp(argv[1], "add") == 0)
{
return ipx_add_route(argc - 2, argv + 2);
} else if (strcasecmp(argv[1], "del") == 0)
{
return ipx_del_route(argc - 2, argv + 2);
} else {
usage();
return -1;
}
usage();
return 0;
}

93
src/ipxutil.c Normal file
View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 1999 Petr Vandrovec <vandrove@vc.cvut.cz>
* All Rights Reserved.
*
* See file COPYING for details.
*/
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <ncp/kernel/ipx.h>
#include <sys/types.h>
#include "ipxutil.h"
/* caller must fill sockaddr_ipx with default values... */
/* it parses string in form NETWORK:NODE/PORT into sockaddr_ipx structure */
/* you can modify parser by flags: SSIPX_NETWORK = network present
SSIPX_NODE = node present
SSIPX_PORT = port present
separators (:, /) are optional if preceeding parts are not expected */
/* return value: SSIPX_NONE if nothing usable was found, otherwise
combination of SSIPX_* reports, what was found and successfully parsed */
int
sscanf_ipx_addr(struct sockaddr_ipx *sipx, const char* addr, int flags) {
u_int32_t netnum;
char* ptr;
int retval = SSIPX_NONE;
/* skip leading spaces... should we? */
while (*addr && isspace(*addr))
addr++;
if (!*addr)
return retval; /* nothing found */
if (flags & SSIPX_NETWORK) {
netnum = strtoul(addr, &ptr, 16);
if (ptr != addr) {
sipx->sipx_network = htonl(netnum);
retval |= SSIPX_NETWORK; /* network was specified */
addr = ptr;
}
}
if (flags & SSIPX_NODE) {
if ((*addr == ':') || !(flags & SSIPX_NETWORK)) {
u_int16_t hi;
u_int32_t lo;
unsigned int c;
const char* scn;
/* node... */
hi = 0;
lo = 0;
if (*addr == ':')
addr++;
scn = addr;
while (isxdigit(c=*scn)) {
scn++;
hi = (hi << 4) | ((lo >> 28) & 0x0F);
c -= '0';
if (c > 9)
c = (c + '0' - 'A' + 10) & 0x0F;
lo = (lo << 4) | c;
}
if (addr != scn) {
sipx->sipx_node[0] = hi >> 8;
sipx->sipx_node[1] = hi;
sipx->sipx_node[2] = lo >> 24;
sipx->sipx_node[3] = lo >> 16;
sipx->sipx_node[4] = lo >> 8;
sipx->sipx_node[5] = lo;
retval |= SSIPX_NODE;
addr = scn;
} /* else syntax error(node empty) */
}
}
if (flags & SSIPX_PORT) {
if ((*addr == '/') || (*addr == ':') ||
!(flags & (SSIPX_NETWORK|SSIPX_NODE))) {
u_int16_t sock;
/* socket... */
if ((*addr == '/') || (*addr == ':'))
addr++;
sock = strtoul(addr, &ptr, 16);
if (ptr != addr) {
sipx->sipx_port = sock;
retval |= SSIPX_PORT;
addr = ptr;
} /* else syntax error(socket empty) */
}
}
/* if (*addr) syntax error(data after end of address) */
return retval;
}

19
src/ipxutil.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 1999 Petr Vandrovec <vandrove@vc.cvut.cz>
* All Rights Reserved.
*
* See file COPYING for details.
*/
#ifndef __IPXUTIL_H__
#define __IPXUTIL_H__
#define SSIPX_NONE 0
#define SSIPX_NETWORK 1
#define SSIPX_NODE 2
#define SSIPX_PORT 4
int
sscanf_ipx_addr(struct sockaddr_ipx *sipx, const char* addr, int flags);
#endif /* __IPXUTIL_H__ */

89
src/netlink.h Normal file
View File

@@ -0,0 +1,89 @@
/* this is Linux 2.3.3 kernel include file with:
(1) removed __KERNEL__ part
(2) __uXX -> u_intXX_t
*/
#ifndef __LINUX_NETLINK_H
#define __LINUX_NETLINK_H
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_SKIP 1 /* Reserved for ENskip */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_ARPD 8
#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
#define NETLINK_IP6_FW 13
#define NETLINK_TAPBASE 16 /* 16 to 31 are ethertap */
#define MAX_LINKS 32
struct sockaddr_nl
{
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
u_int32_t nl_pid; /* process pid */
u_int32_t nl_groups; /* multicast groups mask */
};
struct nlmsghdr
{
u_int32_t nlmsg_len; /* Length of message including header */
u_int16_t nlmsg_type; /* Message content */
u_int16_t nlmsg_flags; /* Additional flags */
u_int32_t nlmsg_seq; /* Sequence number */
u_int32_t nlmsg_pid; /* Sending process PID */
};
/* Flags values */
#define NLM_F_REQUEST 1 /* It is request message. */
#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
#define NLM_F_ACK 4 /* If succeed, reply with ack */
#define NLM_F_ECHO 8 /* Echo this request */
/* Modifiers to GET request */
#define NLM_F_ROOT 0x100 /* specify tree root */
#define NLM_F_MATCH 0x200 /* return all matching */
#define NLM_F_ATOMIC 0x400 /* atomic GET */
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
/* Modifiers to NEW request */
#define NLM_F_REPLACE 0x100 /* Override existing */
#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
#define NLM_F_APPEND 0x800 /* Add to end of list */
/*
4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
4.4BSD CHANGE NLM_F_REPLACE
True CHANGE NLM_F_CREATE|NLM_F_REPLACE
Append NLM_F_CREATE
Check NLM_F_EXCL
*/
#define NLMSG_ALIGNTO 4
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
#define NLMSG_OK(nlh,len) ((len) > 0 && (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
(nlh)->nlmsg_len <= (len))
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
#define NLMSG_NOOP 0x1 /* Nothing. */
#define NLMSG_ERROR 0x2 /* Error */
#define NLMSG_DONE 0x3 /* End of a dump */
#define NLMSG_OVERRUN 0x4 /* Data lost */
struct nlmsgerr
{
int error;
struct nlmsghdr msg;
};
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
#endif /* __LINUX_NETLINK_H */

22
src/nls.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef IPX_UTILS_NLS_H
#define IPX_UTILS_NLS_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(HAVE_LIBINTL_H) && defined(HAVE_GETTEXT)
# include <libintl.h>
#else
# define gettext(String) (String)
#endif
#ifndef _
# define _(String) gettext(String)
#endif
#ifndef N_
# define N_(String) (String)
#endif
#endif /* IPX_UTILS_NLS_H */

1
stamp-h1 Normal file
View File

@@ -0,0 +1 @@
timestamp for config.h

45
tools/README Normal file
View File

@@ -0,0 +1,45 @@
This is a VERY stupid packet sniffer for IPX ethernet packets.
=============================================
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! S E C U R I T Y W A R N I N G ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
=============================================
If you are using unencrypted passwords, and use this tool to send a
dump to somebody else or store it on a computer, you might very well
store passwords there. So, be VERY careful! This is exactly the kind
of tools Novell designed the encrypted passwords for (or against).
I hacked it together to be able to help people with problems with
ncpfs. The socket handling was taken from Statnet-2.0.
You can use it to watch commercial NetWare clients when they talk to
servers. I divided the program into 2 parts, ipxdump and ipxparse.
ipxdump simply pumps all the IPX frames it receives to stdout.
If you use ipxdump to watch a workstation, you can use the simple
filter function ipxdump provides. You can call ipxdump with the node
address of the workstation you want to watch. This way only the
packets this workstation sends and receives are monitored. As an
example, I call ipxdump as
./ipxdump 00001B038B11
to look at my 286/10MHz test 'workstation'. ipxdump still generates
huge amounts of data, so you should be very careful to start it just
before you perform the operation (such as file creation for OS/2
clients with NW4.1 as a server, or a 'dir' on a directory with long
and short file names, or an encrypted password change ;-)) and stop it
directly after that. And, please gzip -9 and uuencode it before you
send it to anybody.
ipxparse will eventually take apart the dump that ipxdump
generates. They can as well be used in a pipe. Currently ipxparse does
not do anything sensible, but that will definitely change.
Volker Lendecke
<lendecke@namu01.gwdg.de>

305
tools/ipxdump.c Normal file
View File

@@ -0,0 +1,305 @@
/*
ipxdump.c
Copyright 1996 Volker Lendecke, Goettingen, Germany
Copyright 1999, 2001 Petr Vandrovec, Prague, Czech Republic
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., 675 Mass Ave, Cambridge, MA 02139, USA.
Revision History:
1.01 1999, December, 15 Petr Vandrovec <vandrove@vc.cvut.cz>
Use sigaction instead of signal, so ^C works
immediately and not after next frame comes
(bsd vs. sysv signal() semantic bug)
1.02 2001, July 15 Petr Vandrovec <vandrove@vc.cvut.cz>
Add #include <stdlib> to fix some warnings.
*/
#include "config.h"
#include <unistd.h>
#include <sys/types.h>
#include <ncp/ext/socket.h>
/* TBD */
#include <netinet/in.h>
#ifdef HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#else
#include <linux/if_ether.h>
#endif
#include <string.h>
#include <sys/ioctl.h>
#include <ncp/kernel/if.h>
#include <signal.h>
#include <stdlib.h>
/* TBD */
#include <netinet/ip.h>
/* TBD */
#include <netinet/tcp.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include "ipxutil.h"
struct ipx_address
{
IPXNet net __attribute__((packed));
IPXNode node __attribute__((packed));
IPXPort sock __attribute__((packed));
};
struct ipx_packet
{
unsigned short ipx_checksum __attribute__((packed));
#define IPX_NO_CHECKSUM 0xFFFF
unsigned short ipx_pktsize __attribute__((packed));
unsigned char ipx_tctrl __attribute__((packed));
unsigned char ipx_type __attribute__((packed));
#define IPX_TYPE_UNKNOWN 0x00
#define IPX_TYPE_RIP 0x01 /* may also be 0 */
#define IPX_TYPE_SAP 0x04 /* may also be 0 */
#define IPX_TYPE_SPX 0x05 /* Not yet implemented */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */
struct ipx_address ipx_dest __attribute__((packed));
struct ipx_address ipx_source __attribute__((packed));
};
void handle_frame(unsigned char *buf, int length, struct sockaddr *saddr);
void handle_ipx(const char *frame, unsigned char *buf);
static int filter = 0;
static int allframes = 0;
static IPXNode filter_node;
static const char* progname;
static void usage(void) {
fprintf(stderr, "usage: %s [-r] [-d device] [node]\n", progname);
}
static int exit_request = 0;
static void
int_handler(int dummy)
{
exit_request = 1;
(void)dummy;
}
int
main(int argc, char *argv[])
{
int sd;
struct ifreq ifr, oldifr;
const char *device = "eth0";
struct sockaddr saddr;
int sizeaddr;
unsigned char buf[4096];
int length;
int opt;
struct sigaction saint;
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
saint.sa_handler = int_handler;
saint.sa_flags = 0;
sigemptyset(&saint.sa_mask);
sigaction(SIGINT, &saint, NULL);
while ((opt = getopt(argc, argv, "rd:h")) != -1) {
switch (opt) {
case 'r':allframes = 1;
break;
case 'd':device = optarg;
break;
case 'h':usage();
return 5;
case ':':;
case '?':break;
default: printf("?? unknown option returned by getopt\n");
break;
}
}
if (optind < argc)
{
if (ipx_sscanf_node(argv[optind], filter_node) != 0)
{
usage();
exit(1);
}
filter = 1;
}
setvbuf(stdout, NULL, _IOLBF, 0);
// if ((sd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0)
if ((sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
{
perror("Can't get socket");
fprintf(stderr, "You must run %s as root\n", progname);
exit(1);
}
/* SET PROMISC */
strcpy(oldifr.ifr_name, device);
if (ioctl(sd, SIOCGIFFLAGS, &oldifr) < 0)
{
close(sd);
perror("Can't get flags");
exit(2);
}
/* This should be rewritten to cooperate with other net tools */
ifr = oldifr;
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl(sd, SIOCSIFFLAGS, &ifr) < 0)
{
close(sd);
perror("Can't set flags");
exit(3);
}
while (exit_request == 0)
{
/* This is the main data-gathering loop; keep it small
and fast */
sizeaddr = sizeof(saddr);
length = recvfrom(sd, buf, sizeof(buf), 0,
&saddr, &sizeaddr);
if (length < 0)
continue;
if (allframes) {
unsigned char* ptr = buf;
if (filter) {
if (memcmp(filter_node, buf, 6)&&memcmp(filter_node, buf+6, 6))
continue;
}
printf("raweth ");
while (length--) printf("%02X", *ptr++);
printf("\n");
} else {
handle_frame(buf, length, &saddr);
}
}
/* This should be rewritten to cooperate with other net tools */
if (ioctl(sd, SIOCSIFFLAGS, &oldifr) < 0)
{
close(sd);
perror("Can't set flags");
exit(4);
}
close(sd);
return 0;
}
void
handle_ipx(const char *frame, unsigned char *buf)
{
int i;
struct ipx_packet *h = (struct ipx_packet *) buf;
struct sockaddr_ipx s_addr;
struct sockaddr_ipx d_addr;
int length = ntohs(h->ipx_pktsize);
memset(&s_addr, 0, sizeof(s_addr));
memset(&d_addr, 0, sizeof(d_addr));
memcpy(s_addr.sipx_node, h->ipx_source.node, sizeof(s_addr.sipx_node));
s_addr.sipx_port = h->ipx_source.sock;
s_addr.sipx_network = h->ipx_source.net;
memcpy(d_addr.sipx_node, h->ipx_dest.node, sizeof(d_addr.sipx_node));
d_addr.sipx_port = h->ipx_dest.sock;
d_addr.sipx_network = h->ipx_dest.net;
if (filter != 0)
{
if ((memcmp(filter_node, s_addr.sipx_node,
sizeof(filter_node)) != 0)
&& (memcmp(filter_node, d_addr.sipx_node,
sizeof(filter_node)) != 0))
{
/* Not for us */
return;
}
}
printf("%s ", frame);
for (i = 0; i < length; i++)
{
printf("%2.2X", buf[i]);
}
printf("\n");
if (!isatty(STDOUT_FILENO))
{
fflush(stdout);
}
}
void
handle_other(unsigned char *buf, int length, struct sockaddr *saddr)
{
struct ethhdr *eth = (struct ethhdr *) buf;
unsigned char *p = &(buf[sizeof(struct ethhdr)]);
if (ntohs(eth->h_proto) < 1536)
{
/* This is a magic hack to spot IPX packets. Older
* Novell breaks the protocol design and runs IPX over
* 802.3 without an 802.2 LLC layer. We look for FFFF
* which isnt a used 802.2 SSAP/DSAP. This won't work
* for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *) p == 0xffff)
{
handle_ipx("802.3", p);
return;
}
if ((*(unsigned short *) p == htons(0xe0e0))
&& (p[2] == 0x03))
{
handle_ipx("802.2", p + 3);
return;
}
if (memcmp(p, "\252\252\003\000\000\000\201\067", 8) == 0)
{
handle_ipx("snap", p + 8);
return;
}
}
}
void
handle_frame(unsigned char *buf, int length, struct sockaddr *saddr)
{
/* Ethernet packet type ID field */
unsigned short packet_type = ((struct ethhdr *) buf)->h_proto;
switch (htons(packet_type))
{
case ETH_P_IPX:
handle_ipx("EtherII", &(buf[sizeof(struct ethhdr)]));
break;
default:
handle_other(buf, length, saddr);
break;
}
}

1140
tools/ipxparse.c Normal file

File diff suppressed because it is too large Load Diff

133
tools/ipxutil.c Normal file
View File

@@ -0,0 +1,133 @@
/*
IPX support library - general functions
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <netinet/in.h>
#include "ipxutil.h"
void
ipx_fprint_node(FILE * file, IPXNode node)
{
fprintf(file, "%02X%02X%02X%02X%02X%02X",
(unsigned char) node[0],
(unsigned char) node[1],
(unsigned char) node[2],
(unsigned char) node[3],
(unsigned char) node[4],
(unsigned char) node[5]
);
}
void
ipx_fprint_network(FILE * file, IPXNet net)
{
fprintf(file, "%08lX", (unsigned long)net);
}
void
ipx_fprint_port(FILE * file, IPXPort port)
{
fprintf(file, "%04X", port);
}
void
ipx_fprint_saddr(FILE * file, struct sockaddr_ipx *sipx)
{
ipx_fprint_network(file, ntohl(sipx->sipx_network));
fprintf(file, ":");
ipx_fprint_node(file, sipx->sipx_node);
fprintf(file, ":");
ipx_fprint_port(file, ntohs(sipx->sipx_port));
}
void
ipx_print_node(IPXNode node)
{
ipx_fprint_node(stdout, node);
}
void
ipx_print_network(IPXNet net)
{
ipx_fprint_network(stdout, net);
}
void
ipx_print_port(IPXPort port)
{
ipx_fprint_port(stdout, port);
}
void
ipx_print_saddr(struct sockaddr_ipx *sipx)
{
ipx_fprint_saddr(stdout, sipx);
}
void
ipx_assign_node(IPXNode dest, IPXNode src)
{
memcpy(dest, src, sizeof(IPXNode));
}
int
ipx_node_equal(IPXNode n1, IPXNode n2)
{
return memcmp(n1, n2, sizeof(IPXNode)) == 0;
}
int
ipx_sscanf_node(char *buf, IPXNode node)
{
int i;
int n[6];
if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
&(n[0]), &(n[1]), &(n[2]),
&(n[3]), &(n[4]), &(n[5]))) != 6)
{
return -1;
}
for (i = 0; i < 6; i++)
{
node[i] = n[i];
}
return 0;
}
int
ipx_sscanf_net(char *buf, IPXNet * target)
{
unsigned long net;
if (sscanf(buf, "%8lX", &net) == 1)
{
*target = net;
return 0;
}
return -1;
}
IPXNode ipx_this_node =
{0, 0, 0, 0, 0, 0};
IPXNode ipx_broadcast_node =
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
char ipx_err_string[IPX_MAX_ERROR + 1] = "no error detected";

65
tools/ipxutil.h Normal file
View File

@@ -0,0 +1,65 @@
/*
IPX support library
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __IPXUTIL_H__
#define __IPXUTIL_H__
#include <stdio.h>
#include <ncp/kernel/ipx.h>
#define IPX_MAX_ERROR (255)
#define IPX_THIS_NET (0)
#define IPX_THIS_NODE (ipx_this_node)
#define IPX_BROADCAST (ipx_broadcast_node)
#define IPX_AUTO_PORT (0)
#define IPX_USER_PTYPE (0)
#define IPX_IS_INTERNAL (1)
typedef u_int8_t IPXNode[6];
typedef u_int32_t IPXNet;
typedef u_int16_t IPXPort;
typedef u_int16_t hop_t;
typedef u_int16_t tick_t;
void ipx_print_node(IPXNode node);
void ipx_print_network(IPXNet net);
void ipx_print_port(IPXPort port);
void ipx_print_saddr(struct sockaddr_ipx *sipx);
void ipx_fprint_node(FILE * file, IPXNode node);
void ipx_fprint_network(FILE * file, IPXNet net);
void ipx_fprint_port(FILE * file, IPXPort port);
void ipx_fprint_saddr(FILE * file, struct sockaddr_ipx *sipx);
int ipx_sscanf_node(char *buf, IPXNode node);
int ipx_sscanf_net(char *buf, IPXNet * target);
void ipx_assign_node(IPXNode dest, IPXNode src);
int ipx_node_equal(IPXNode n1, IPXNode n2);
extern IPXNode ipx_this_node;
extern IPXNode ipx_broadcast_node;
extern char ipx_err_string[IPX_MAX_ERROR + 1];
#endif