Merge branch 'master' of github.com:jclehner/nmrpflash
This commit is contained in:
commit
c0c951f4a8
8 changed files with 195 additions and 50 deletions
7
Makefile
7
Makefile
|
|
@ -1,13 +1,14 @@
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
VERSION = $(shell git describe --always | tail -c +2)
|
VERSION := $(shell if [ -d .git ] && which git 2>&1 > /dev/null; then git describe --always | tail -c +2; else echo $$STANDALONE_VERSION; fi)
|
||||||
LIBS = -lpcap
|
LIBS = -lpcap
|
||||||
CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\"
|
CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\"
|
||||||
LDFLAGS += $(LIBS)
|
LDFLAGS += $(LIBS)
|
||||||
|
|
||||||
ifeq ($(shell uname -s),Linux)
|
ifeq ($(shell uname -s),Linux)
|
||||||
CFLAGS += $(shell pkg-config libnl-route-3.0 --cflags)
|
CFLAGS += $(shell $(PKG_CONFIG) libnl-route-3.0 --cflags)
|
||||||
LIBS += $(shell pkg-config libnl-route-3.0 --libs)
|
LIBS += $(shell $(PKG_CONFIG) libnl-route-3.0 --libs)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(shell uname -s),Darwin)
|
ifeq ($(shell uname -s),Darwin)
|
||||||
|
|
|
||||||
33
README-R7000.md
Normal file
33
README-R7000.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
Some helpful hints for putting firmware on the Netgear R7000
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
* As of the writing of this, July 2020, the R7000's web interface does not let you downgrade its firmware, or run 3rd party firmware on it.
|
||||||
|
* Older versions of the R7000's firmware do allow you to flash 3rd party firmware.
|
||||||
|
* You can use nrmpflash to downgrade router's firmware, for example R7000-V1.0.3.56_1.1.25.
|
||||||
|
|
||||||
|
Here is an example set of steps
|
||||||
|
1. Plug in your router, go through the regular stock web interface setup. Note if the router's IP address is now 192.168.1.1 or 10.0.0.1
|
||||||
|
2. Connect computer your computer to LAN1 with an ethernet cable
|
||||||
|
3. At the command prompt on your computer, run:
|
||||||
|
`sudo nmrpflash -v -i YOUR_ADAPTER_NAME -f R7000-V1.0.3.56_1.1.25.chk -t 10000 -T 10000 -A 10.0.0.2 -a 10.0.0.1`
|
||||||
|
* Note 1: The instructions from README.md that tell you how to find YOUR_ADAPTER_NAME.
|
||||||
|
* Note 2: if your router's IP address was 192.168.1.1 then swap out 10.0.0.x with 192.168.1.x for the two IP addresses above
|
||||||
|
4. Right after running the command, power on your router. Your router checks for the nmrpflash server on boot. If all goes well you should see this:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo nmrpflash -v -i enp0s25 -f R7000-V1.0.3.56_1.1.25.chk -t 10000 -T 10000 -A 10.0.0.2 -a 10.0.0.1
|
||||||
|
Adding 10.0.0.2 to interface enp0s25.
|
||||||
|
Advertising NMRP server on enp0s25 ... /
|
||||||
|
Received configuration request from ab:cd:ef:12:34:56.
|
||||||
|
Sending configuration: 10.0.0.1/24.
|
||||||
|
Received upload request without filename.
|
||||||
|
Using remote filename 'R7000-V1.0.3.56_1.1.25.chk'.
|
||||||
|
Uploading R7000-V1.0.3.56_1.1.25.chk ... OK
|
||||||
|
Waiting for remote to respond.
|
||||||
|
Received keep-alive request (19).
|
||||||
|
Remote finished. Closing connection.
|
||||||
|
Reboot your device now.
|
||||||
|
|
||||||
|
```
|
||||||
|
5. Reboot the device. You now have old firwmare, congratulations.
|
||||||
|
|
||||||
63
README.md
63
README.md
|
|
@ -3,7 +3,7 @@ nmrpflash - Netgear Unbrick Utility
|
||||||
|
|
||||||
`nmrpflash` uses Netgear's [NMRP protocol](http://www.chubb.wattle.id.au/PeterChubb/nmrp.html)
|
`nmrpflash` uses Netgear's [NMRP protocol](http://www.chubb.wattle.id.au/PeterChubb/nmrp.html)
|
||||||
to flash a new firmware image to a compatible device. It has been successfully used on a Netgear
|
to flash a new firmware image to a compatible device. It has been successfully used on a Netgear
|
||||||
EX2700, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, but is likely to be compatible
|
EX2700, EX6120, EX6150v2, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, WNDR3800, but is likely to be compatible
|
||||||
with many other Netgear devices.
|
with many other Netgear devices.
|
||||||
|
|
||||||
Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available
|
Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available
|
||||||
|
|
@ -13,16 +13,17 @@ Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available
|
||||||
```
|
```
|
||||||
Usage: nmrpflash [OPTIONS...]
|
Usage: nmrpflash [OPTIONS...]
|
||||||
|
|
||||||
Options (-i and -f and/or -c are mandatory):
|
Options (-i, and -f or -c are mandatory):
|
||||||
-a <ipaddr> IP address to assign to target device
|
-a <ipaddr> IP address to assign to target device
|
||||||
-A <ipaddr> IP address to assign to interface
|
-A <ipaddr> IP address to assign to selected interface
|
||||||
|
-B Blind mode (don't wait for response packets)
|
||||||
-c <command> Command to run before (or instead of) TFTP upload
|
-c <command> Command to run before (or instead of) TFTP upload
|
||||||
-f <firmware> Firmware file
|
-f <firmware> Firmware file
|
||||||
-F <filename> Remote filename to use during TFTP upload
|
-F <filename> Remote filename to use during TFTP upload
|
||||||
-i <interface> Network interface directly connected to device
|
-i <interface> Network interface directly connected to device
|
||||||
-m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)
|
-m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)
|
||||||
-M <netmask> Subnet mask to assign to target device
|
-M <netmask> Subnet mask to assign to target device
|
||||||
-t <timeout> Timeout (in milliseconds) for regular messages
|
-t <timeout> Timeout (in milliseconds) for NMRP packets
|
||||||
-T <timeout> Time (seconds) to wait after successfull TFTP upload
|
-T <timeout> Time (seconds) to wait after successfull TFTP upload
|
||||||
-p <port> Port to use for TFTP upload
|
-p <port> Port to use for TFTP upload
|
||||||
-R <region> Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP)
|
-R <region> Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP)
|
||||||
|
|
@ -38,6 +39,12 @@ Your Netgear router must be connected to your network using an
|
||||||
Ethernet cable. The device running `nmrpflash` must be connected
|
Ethernet cable. The device running `nmrpflash` must be connected
|
||||||
to the same network, using either Wi-Fi or Ethernet.
|
to the same network, using either Wi-Fi or Ethernet.
|
||||||
|
|
||||||
|
Usage sequence of events:
|
||||||
|
1. Turn off the router
|
||||||
|
2. Connect ethernet cable from computer to router's LAN1
|
||||||
|
3. Run nmrpflash on command line
|
||||||
|
4. Turn on the router.
|
||||||
|
|
||||||
All available network interfaces can be listed using
|
All available network interfaces can be listed using
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -93,9 +100,16 @@ C:\> net start npf
|
||||||
|
|
||||||
###### "No response after 60 seconds. Bailing out."
|
###### "No response after 60 seconds. Bailing out."
|
||||||
|
|
||||||
The router did not respond. Try rebooting the device and run `nmrpflash` again.
|
The router did not respond. Always run `nmrpflash` in the sequence
|
||||||
You could also try running `nmrpflash` with `-m` and specify your router's
|
described above!
|
||||||
MAC address. It's also possible that your device does not support the NMRP protocol.
|
|
||||||
|
If that still doesn't work, you can try "blind mode", which can be
|
||||||
|
invoked using `-B`. Note that you also have to specify your router's
|
||||||
|
mac address using `-m xx:xx:xx:xx:xx:xx`. Also beware that in this mode,
|
||||||
|
careful timing between running `nmrpflash` and turning on the router may
|
||||||
|
be required!
|
||||||
|
|
||||||
|
It's also possible that your device does not support the NMRP protocol.
|
||||||
|
|
||||||
###### "Timeout while waiting for ACK(0)/OACK."
|
###### "Timeout while waiting for ACK(0)/OACK."
|
||||||
|
|
||||||
|
|
@ -157,6 +171,36 @@ By default, file transfers using TFTP are limited to `65535 * 512` bytes
|
||||||
(almost 32 MiB). Uploading files exceeding this limit might fail, depending
|
(almost 32 MiB). Uploading files exceeding this limit might fail, depending
|
||||||
on the device.
|
on the device.
|
||||||
|
|
||||||
|
###### "Ignoring extra upload request."
|
||||||
|
|
||||||
|
Extraneous upload requests are usually sent by the device if the image validation
|
||||||
|
failed. Some possible causes are:
|
||||||
|
|
||||||
|
* If you downloaded a firmware that's contained in an archive (a `.zip` for
|
||||||
|
example), you must extract this file, and then use the contained firmware file
|
||||||
|
as the argument to the `-f` parameter. Some examples for file extensions used
|
||||||
|
for firmware: `.chk`, `.bin`, `.trx`, `.img`.
|
||||||
|
|
||||||
|
* Some devices prevent you from downgrading the firmware. See if it works with
|
||||||
|
the latest version available for your device. If you're already using the latest
|
||||||
|
version, it might be possible to patch the version info of the firmware file. A
|
||||||
|
future version of `nmrpflash` might incorporate an auto-patch feature for these
|
||||||
|
cases.
|
||||||
|
|
||||||
|
* Your device might expect a different image format for `nmrpflash` than when
|
||||||
|
flashing via the web interface.
|
||||||
|
|
||||||
|
###### "bind: Cannot assign requested address"
|
||||||
|
|
||||||
|
Specify the address of the router, and address of your computer, using
|
||||||
|
`-A` and `-a`. For example:
|
||||||
|
|
||||||
|
`-A 10.0.0.2 -a 10.0.0.1`
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
`-A 192.168.1.2 -a 192.168.1.1`
|
||||||
|
|
||||||
### Building and installing
|
### Building and installing
|
||||||
###### Linux, Mac OS X, BSDs
|
###### Linux, Mac OS X, BSDs
|
||||||
|
|
||||||
|
|
@ -173,4 +217,9 @@ project file (`nmrpflash.dev`). Download the latest
|
||||||
and extract it into the root folder of the `nmrpflash` sources.
|
and extract it into the root folder of the `nmrpflash` sources.
|
||||||
|
|
||||||
|
|
||||||
|
### Donate
|
||||||
|
|
||||||
|
You can [buy me a coffee](https://www.buymeacoffee.com/jclehner) if you want, but please consider
|
||||||
|
donating the money for charity instead - [Médecins Sans Frontiers](https://www.msf.org/donate) comes to mind,
|
||||||
|
but any other organization, local or international, that you think deserves support will do. Thank you!
|
||||||
|
|
||||||
|
|
|
||||||
27
main.c
27
main.c
|
|
@ -28,16 +28,17 @@ void usage(FILE *fp)
|
||||||
fprintf(fp,
|
fprintf(fp,
|
||||||
"Usage: nmrpflash [OPTIONS...]\n"
|
"Usage: nmrpflash [OPTIONS...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options (-i, -f and/or -c are mandatory):\n"
|
"Options (-i, and -f or -c are mandatory):\n"
|
||||||
" -a <ipaddr> IP address to assign to target device\n"
|
" -a <ipaddr> IP address to assign to target device\n"
|
||||||
" -A <ipaddr> IP address to assign to seleted interface\n"
|
" -A <ipaddr> IP address to assign to selected interface\n"
|
||||||
|
" -B Blind mode (don't wait for response packets)\n"
|
||||||
" -c <command> Command to run before (or instead of) TFTP upload\n"
|
" -c <command> Command to run before (or instead of) TFTP upload\n"
|
||||||
" -f <firmware> Firmware file\n"
|
" -f <firmware> Firmware file\n"
|
||||||
" -F <filename> Remote filename to use during TFTP upload\n"
|
" -F <filename> Remote filename to use during TFTP upload\n"
|
||||||
" -i <interface> Network interface directly connected to device\n"
|
" -i <interface> Network interface directly connected to device\n"
|
||||||
" -m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)\n"
|
" -m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)\n"
|
||||||
" -M <netmask> Subnet mask to assign to target device\n"
|
" -M <netmask> Subnet mask to assign to target device\n"
|
||||||
" -t <timeout> Timeout (in milliseconds) for regular messages\n"
|
" -t <timeout> Timeout (in milliseconds) for NMRP packets\n"
|
||||||
" -T <timeout> Time (seconds) to wait after successfull TFTP upload\n"
|
" -T <timeout> Time (seconds) to wait after successfull TFTP upload\n"
|
||||||
" -p <port> Port to use for TFTP upload\n"
|
" -p <port> Port to use for TFTP upload\n"
|
||||||
#ifdef NMRPFLASH_SET_REGION
|
#ifdef NMRPFLASH_SET_REGION
|
||||||
|
|
@ -128,9 +129,9 @@ void require_admin()
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int c, val, max;
|
int c, val, max;
|
||||||
int list = 0;
|
bool list = false, have_dest_mac = false;
|
||||||
struct nmrpd_args args = {
|
struct nmrpd_args args = {
|
||||||
.rx_timeout = 200,
|
.rx_timeout = 200 * 1000,
|
||||||
.ul_timeout = 5 * 60 * 1000,
|
.ul_timeout = 5 * 60 * 1000,
|
||||||
.tftpcmd = NULL,
|
.tftpcmd = NULL,
|
||||||
.file_local = NULL,
|
.file_local = NULL,
|
||||||
|
|
@ -143,6 +144,7 @@ int main(int argc, char **argv)
|
||||||
.op = NMRP_UPLOAD_FW,
|
.op = NMRP_UPLOAD_FW,
|
||||||
.port = 69,
|
.port = 69,
|
||||||
.region = NULL,
|
.region = NULL,
|
||||||
|
.blind = false,
|
||||||
};
|
};
|
||||||
#ifdef NMRPFLASH_WINDOWS
|
#ifdef NMRPFLASH_WINDOWS
|
||||||
char *newpath = NULL;
|
char *newpath = NULL;
|
||||||
|
|
@ -179,7 +181,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "a:A:c:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) {
|
while ((c = getopt(argc, argv, "a:A:Bc:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) {
|
||||||
max = 0x7fffffff;
|
max = 0x7fffffff;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'a':
|
case 'a':
|
||||||
|
|
@ -188,6 +190,9 @@ int main(int argc, char **argv)
|
||||||
case 'A':
|
case 'A':
|
||||||
args.ipaddr_intf = optarg;
|
args.ipaddr_intf = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'B':
|
||||||
|
args.blind = true;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
args.tftpcmd = optarg;
|
args.tftpcmd = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
@ -202,6 +207,7 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
args.mac = optarg;
|
args.mac = optarg;
|
||||||
|
have_dest_mac = true;
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
args.ipmask = optarg;
|
args.ipmask = optarg;
|
||||||
|
|
@ -227,7 +233,7 @@ int main(int argc, char **argv)
|
||||||
if (c == 'p') {
|
if (c == 'p') {
|
||||||
args.port = val;
|
args.port = val;
|
||||||
} else if (c == 't') {
|
} else if (c == 't') {
|
||||||
args.rx_timeout = val;
|
args.rx_timeout = val * 1000;
|
||||||
} else if (c == 'T') {
|
} else if (c == 'T') {
|
||||||
args.ul_timeout = val * 1000;
|
args.ul_timeout = val * 1000;
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +247,7 @@ int main(int argc, char **argv)
|
||||||
++verbosity;
|
++verbosity;
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
list = 1;
|
list = true;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(stdout);
|
usage(stdout);
|
||||||
|
|
@ -267,6 +273,11 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.blind && !have_dest_mac) {
|
||||||
|
fprintf(stderr, "Error: use of -B requires -m <mac>.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NMRPFLASH_FUZZ
|
#ifndef NMRPFLASH_FUZZ
|
||||||
if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf)) {
|
if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf)) {
|
||||||
usage(stderr);
|
usage(stderr);
|
||||||
|
|
|
||||||
88
nmrp.c
88
nmrp.c
|
|
@ -357,11 +357,11 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
uint16_t region;
|
uint16_t region;
|
||||||
char *filename;
|
char *filename;
|
||||||
time_t beg;
|
time_t beg;
|
||||||
int i, status, ulreqs, expect, upload_ok, autoip, kareqs;
|
int i, timeout, status, ulreqs, expect, upload_ok, autoip, ka_reqs, fake;
|
||||||
struct ethsock *sock;
|
struct ethsock *sock;
|
||||||
struct ethsock_ip_undo *ip_undo = NULL;
|
struct ethsock_ip_undo *ip_undo = NULL;
|
||||||
struct ethsock_arp_undo *arp_undo = NULL;
|
struct ethsock_arp_undo *arp_undo = NULL;
|
||||||
uint32_t intf_addr;
|
uint32_t intf_addr = 0;
|
||||||
void (*sigh_orig)(int);
|
void (*sigh_orig)(int);
|
||||||
struct in_addr ipaddr;
|
struct in_addr ipaddr;
|
||||||
struct in_addr ipmask;
|
struct in_addr ipmask;
|
||||||
|
|
@ -385,8 +385,13 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
|
|
||||||
if (!args->ipaddr) {
|
if (!args->ipaddr) {
|
||||||
autoip = true;
|
autoip = true;
|
||||||
/* The MAC of the device that was used to test this utility starts
|
/* A random IP address. The MAC of the first device that was
|
||||||
* with a4:2b:8c, hence 164 (0xa4) and 183 (0x2b + 0x8c)
|
* used to test this utility starts with a4:2b:8c, so we use
|
||||||
|
* 164 (0xa4) and 183 (0x2b + 0x8c).
|
||||||
|
*
|
||||||
|
* These addresses should not cause collisions on most networks,
|
||||||
|
* and if they do, the user is probably "poweruser" enough to
|
||||||
|
* be able to use the -a and -A options.
|
||||||
*/
|
*/
|
||||||
args->ipaddr = "10.164.183.252";
|
args->ipaddr = "10.164.183.252";
|
||||||
|
|
||||||
|
|
@ -477,6 +482,8 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
upload_ok = 0;
|
upload_ok = 0;
|
||||||
|
fake = 0;
|
||||||
|
timeout = args->blind ? 10 : NMRP_INITIAL_TIMEOUT;
|
||||||
beg = time_monotonic();
|
beg = time_monotonic();
|
||||||
|
|
||||||
while (!g_interrupted) {
|
while (!g_interrupted) {
|
||||||
|
|
@ -486,7 +493,6 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
i = (i + 1) & 3;
|
i = (i + 1) & 3;
|
||||||
|
|
||||||
if (pkt_send(sock, &tx) < 0) {
|
if (pkt_send(sock, &tx) < 0) {
|
||||||
xperror("sendto");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,18 +510,34 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
} else {
|
} else {
|
||||||
/* because we don't want nmrpflash's exit status to be zero */
|
/* because we don't want nmrpflash's exit status to be zero */
|
||||||
status = 1;
|
status = 1;
|
||||||
if ((time_monotonic() - beg) >= NMRP_INITIAL_TIMEOUT) {
|
if ((time_monotonic() - beg) >= timeout) {
|
||||||
printf("\nNo response after 60 seconds. Bailing out.\n");
|
printf("\nNo response after %d seconds. ", timeout);
|
||||||
goto out;
|
if (!args->blind) {
|
||||||
|
printf("Bailing out.\n");
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
// we're blind, so fake a response from the MAC specified by -m
|
||||||
|
memcpy(rx.eh.ether_shost, dest, 6);
|
||||||
|
msg_init(&rx.msg, NMRP_C_CONF_REQ);
|
||||||
|
printf("Continuing blindly.");
|
||||||
|
fake = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6);
|
||||||
|
|
||||||
|
if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
expect = NMRP_C_CONF_REQ;
|
expect = NMRP_C_CONF_REQ;
|
||||||
ulreqs = 0;
|
ulreqs = 0;
|
||||||
kareqs = 0;
|
ka_reqs = 0;
|
||||||
|
|
||||||
while (!g_interrupted) {
|
while (!g_interrupted) {
|
||||||
if (expect != NMRP_C_NONE && rx.msg.code != expect) {
|
if (expect != NMRP_C_NONE && rx.msg.code != expect) {
|
||||||
|
|
@ -537,18 +559,14 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region);
|
msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region);
|
||||||
expect = NMRP_C_TFTP_UL_REQ;
|
expect = NMRP_C_TFTP_UL_REQ;
|
||||||
|
|
||||||
printf("Received configuration request from %s.\n",
|
if (!fake) {
|
||||||
mac_to_str(rx.eh.ether_shost));
|
printf("Received configuration request from %s.\n",
|
||||||
|
mac_to_str(rx.eh.ether_shost));
|
||||||
memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6);
|
}
|
||||||
|
|
||||||
printf("Sending configuration: %s/%d.\n",
|
printf("Sending configuration: %s/%d.\n",
|
||||||
args->ipaddr, bitcount(ipmask.s_addr));
|
args->ipaddr, bitcount(ipmask.s_addr));
|
||||||
|
|
||||||
if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case NMRP_C_TFTP_UL_REQ:
|
case NMRP_C_TFTP_UL_REQ:
|
||||||
if (!upload_ok) {
|
if (!upload_ok) {
|
||||||
|
|
@ -575,7 +593,9 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
printf("Received upload request: filename '%s'.\n", filename);
|
printf("Received upload request: filename '%s'.\n", filename);
|
||||||
} else if (!args->file_remote) {
|
} else if (!args->file_remote) {
|
||||||
args->file_remote = leafname(args->file_local);
|
args->file_remote = leafname(args->file_local);
|
||||||
printf("Received upload request without filename.\n");
|
if (!fake) {
|
||||||
|
printf("Received upload request without filename.\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
@ -621,6 +641,10 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
|
if (args->blind) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
printf("Waiting for remote to respond.\n");
|
printf("Waiting for remote to respond.\n");
|
||||||
upload_ok = 1;
|
upload_ok = 1;
|
||||||
ethsock_set_timeout(sock, args->ul_timeout);
|
ethsock_set_timeout(sock, args->ul_timeout);
|
||||||
|
|
@ -636,7 +660,7 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
case NMRP_C_KEEP_ALIVE_REQ:
|
case NMRP_C_KEEP_ALIVE_REQ:
|
||||||
tx.msg.code = NMRP_C_KEEP_ALIVE_ACK;
|
tx.msg.code = NMRP_C_KEEP_ALIVE_ACK;
|
||||||
ethsock_set_timeout(sock, args->ul_timeout);
|
ethsock_set_timeout(sock, args->ul_timeout);
|
||||||
printf("\rReceived keep-alive request (%d). ", ++kareqs);
|
printf("\rReceived keep-alive request (%d). ", ++ka_reqs);
|
||||||
break;
|
break;
|
||||||
case NMRP_C_CLOSE_REQ:
|
case NMRP_C_CLOSE_REQ:
|
||||||
tx.msg.code = NMRP_C_CLOSE_ACK;
|
tx.msg.code = NMRP_C_CLOSE_ACK;
|
||||||
|
|
@ -651,18 +675,13 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.msg.code != NMRP_C_NONE) {
|
if (tx.msg.code != NMRP_C_NONE) {
|
||||||
if (pkt_send(sock, &tx) < 0) {
|
if (pkt_send(sock, &tx) != 0 || tx.msg.code == NMRP_C_CLOSE_REQ) {
|
||||||
xperror("sendto");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.msg.code == NMRP_C_CLOSE_REQ) {
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx.msg.code == NMRP_C_CLOSE_REQ) {
|
if (rx.msg.code == NMRP_C_CLOSE_REQ) {
|
||||||
if (kareqs) {
|
if (ka_reqs) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -673,10 +692,21 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
status = pkt_recv(sock, &rx);
|
status = pkt_recv(sock, &rx);
|
||||||
if (status) {
|
if (status) {
|
||||||
if (status == 2) {
|
if (status == 2) {
|
||||||
fprintf(stderr, "Timeout while waiting for %s.\n",
|
if (!args->blind) {
|
||||||
msg_code_str(expect));
|
fprintf(stderr, "Timeout while waiting for %s.\n",
|
||||||
|
msg_code_str(expect));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fake response
|
||||||
|
msg_init(&rx.msg, expect);
|
||||||
|
memcpy(rx.eh.ether_shost, tx.eh.ether_dhost, 6);
|
||||||
|
fake = 1;
|
||||||
|
} else {
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
goto out;
|
} else {
|
||||||
|
fake = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ethsock_set_timeout(sock, args->rx_timeout);
|
ethsock_set_timeout(sock, args->rx_timeout);
|
||||||
|
|
|
||||||
5
nmrpd.h
5
nmrpd.h
|
|
@ -62,6 +62,10 @@
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef PACKED
|
#ifndef PACKED
|
||||||
#define PACKED __attribute__((packed))
|
#define PACKED __attribute__((packed))
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -92,6 +96,7 @@ struct nmrpd_args {
|
||||||
const char *intf;
|
const char *intf;
|
||||||
const char *mac;
|
const char *mac;
|
||||||
enum nmrp_op op;
|
enum nmrp_op op;
|
||||||
|
bool blind;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
const char *region;
|
const char *region;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
19
tftp.c
19
tftp.c
|
|
@ -317,6 +317,8 @@ inline bool tftp_is_valid_filename(const char *filename)
|
||||||
return strlen(filename) <= 255 && is_netascii(filename);
|
return strlen(filename) <= 255 && is_netascii(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *spinner = "\\|/-";
|
||||||
|
|
||||||
int tftp_put(struct nmrpd_args *args)
|
int tftp_put(struct nmrpd_args *args)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
|
@ -327,6 +329,8 @@ int tftp_put(struct nmrpd_args *args)
|
||||||
const char *file_remote = args->file_remote;
|
const char *file_remote = args->file_remote;
|
||||||
char *val, *end;
|
char *val, *end;
|
||||||
bool rollover;
|
bool rollover;
|
||||||
|
const unsigned rx_timeout = MAX(args->rx_timeout / (args->blind ? 50 : 5), 2000);
|
||||||
|
const unsigned max_timeouts = args->blind ? 3 : 5;
|
||||||
|
|
||||||
sock = -1;
|
sock = -1;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
@ -383,6 +387,7 @@ int tftp_put(struct nmrpd_args *args)
|
||||||
xperror("inet_addr");
|
xperror("inet_addr");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.sin_port = htons(args->port);
|
addr.sin_port = htons(args->port);
|
||||||
|
|
||||||
blksize = 512;
|
blksize = 512;
|
||||||
|
|
@ -429,6 +434,10 @@ int tftp_put(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("%c ", spinner[block & 3]);
|
||||||
|
fflush(stdout);
|
||||||
|
printf("\b\b");
|
||||||
|
|
||||||
pkt_mknum(tx, DATA);
|
pkt_mknum(tx, DATA);
|
||||||
pkt_mknum(tx + 2, block);
|
pkt_mknum(tx + 2, block);
|
||||||
len = read(fd, tx + 4, blksize);
|
len = read(fd, tx + 4, blksize);
|
||||||
|
|
@ -463,11 +472,17 @@ int tftp_put(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = tftp_recvfrom(sock, rx, &port, args->rx_timeout, blksize + 4);
|
ret = tftp_recvfrom(sock, rx, &port, rx_timeout, blksize + 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (!ret) {
|
} else if (!ret) {
|
||||||
if (++timeouts < 5 || (!block && timeouts < 10)) {
|
if (++timeouts < max_timeouts || (!block && timeouts < (max_timeouts * 4))) {
|
||||||
|
continue;
|
||||||
|
} else if (args->blind) {
|
||||||
|
timeouts = 0;
|
||||||
|
// fake an ACK packet
|
||||||
|
pkt_mknum(rx, ACK);
|
||||||
|
pkt_mknum(rx + 2, block);
|
||||||
continue;
|
continue;
|
||||||
} else if (block) {
|
} else if (block) {
|
||||||
fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
|
fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,14 @@ function nmrp_dissect_opt(opt, buffer, tree)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
tree:add(opt_len_f, buffer(2, 2))
|
||||||
|
|
||||||
if opt == 0x01 or opt == 0x0181 then
|
if opt == 0x01 or opt == 0x0181 then
|
||||||
tree:add(buffer(4), "Value: " .. buffer(4):string())
|
tree:add(buffer(4), "Value: " .. buffer(4):string())
|
||||||
elseif opt == 0x02 then
|
elseif opt == 0x02 then
|
||||||
tree:add(buffer(4, 4), "Address: " .. tostring(buffer(4, 4):ipv4()))
|
tree:add(buffer(4, 4), "Address: " .. tostring(buffer(4, 4):ipv4()))
|
||||||
tree:add(buffer(8, 4), "Netmask: " .. tostring(buffer(8, 4):ipv4()))
|
tree:add(buffer(8, 4), "Netmask: " .. tostring(buffer(8, 4):ipv4()))
|
||||||
else
|
else
|
||||||
tree:add(opt_len_f, buffer(2, 2))
|
|
||||||
tree:add(opt_data_f, buffer(4, buffer:len() - 4))
|
tree:add(opt_data_f, buffer(4, buffer:len() - 4))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue