-
-
Save sgarwood/c60883ad2921893d1e9def4bd22b0728 to your computer and use it in GitHub Desktop.
| #include <openssl/sha.h> | |
| #include "stdio.h" | |
| #include <string.h> | |
| #include <linux/ip.h> | |
| #include "lib/tiny-AES-c/aes.h" | |
| #include <netinet/in.h> | |
| #include <sys/socket.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #include "net/ethernet.h" | |
| #include "netinet/ether.h" | |
| #include "arpa/inet.h" | |
| #include <stdio.h> | |
| #include <assert.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/types.h> | |
| #include <linux/in.h> | |
| #include <sys/socket.h> | |
| #include <sys/select.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <openssl/sha.h> | |
| #include <netinet/in.h> | |
| #include <malloc.h> | |
| #include <stdio.h> /* for printf() and fprintf() */ | |
| #include <sys/socket.h> /* for socket(), connect(), sendto(), and recvfrom() */ | |
| #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */ | |
| #include <stdlib.h> /* for atoi() and exit() */ | |
| #include <string.h> /* for memset() */ | |
| #include <unistd.h> /* for close() */ | |
| #define MAXRECVSTRING 116 /* Longest string to receive */ | |
| struct DSBuffer { | |
| uint32_t wanIdx; // 0 idx of WAN? | |
| uint32_t vdslupspeed; // 4 | |
| uint32_t vdsldownspeed; // 8 | |
| uint32_t adsltxcell; // 12 | |
| uint32_t adslrxcell; // 16 | |
| uint32_t adsltxcrce; // 20 | |
| uint32_t adslrxcrce; // 24 | |
| uint32_t dsltype; // 28 | |
| uint32_t timestamp; // 32 | |
| uint32_t vdslsnrup; // 36 | |
| uint32_t vdslsnrdown; // 40 | |
| uint32_t adslloop; // 44 | |
| uint32_t adslsnrm; // 48 | |
| char fw_ver[20]; // 52 | |
| char profile[4]; // 72 --vdslprofile or adslmode | |
| char pad[14]; // | |
| char state[14]; // 90 | |
| // 94 total bytes | |
| // 116 - 104 = bytes left of space | |
| uint8_t a[12]; | |
| }; | |
| void print_upspeed(struct DSBuffer *dslBuffer) { | |
| printf("Upspeed: %u(Kbps)\n", ntohl(dslBuffer->vdslupspeed) / 1000); | |
| } | |
| void print_downspeed(struct DSBuffer *dslBuffer) { | |
| printf("Downspeed: %u(Kbps)\n", ntohl(dslBuffer->vdsldownspeed) / 1000); | |
| } | |
| void print_snrdown(struct DSBuffer *dslBuffer) { | |
| printf("SNR Down: %d\n", ntohl(dslBuffer->vdslsnrdown)); | |
| } | |
| void print_snrup(struct DSBuffer *dslBuffer) { | |
| printf("SNR Up: %d\n", ntohl(dslBuffer->vdslsnrup)); | |
| } | |
| void print_downspeed_in_mbps(struct DSBuffer *dslBuffer) { | |
| // Convert from network byte order (big-endian) to host byte order (assumed LSB) | |
| uint32_t downspeed_host_order = ntohl(dslBuffer->vdsldownspeed); | |
| // Extract the actual download speed in bits per second (bps) | |
| uint32_t downspeed_bps = downspeed_host_order; | |
| // Integer division for Mbps (rounded down) | |
| uint32_t mbps_integer = downspeed_bps / 1000000; // Division by 1 million for Mbps | |
| // Print the download speed in Mbps (rounded down) | |
| printf("Download speed: %u Mbps\n", mbps_integer); | |
| } | |
| void print_dsltype(struct DSBuffer *dslBuffer) { | |
| printf("xDSL Type: %u (6 = vdsl, 1 = adsl)\n", ntohl(dslBuffer->dsltype)); | |
| } | |
| void print_wan(struct DSBuffer *dslBuffer) { | |
| printf("WAN IDX: %u\n", dslBuffer->wanIdx); | |
| } | |
| void print_timestamp(struct DSBuffer *dslBuffer) { | |
| printf("Timestamp: %u\n", ntohl(dslBuffer->timestamp)); | |
| } | |
| void print_fwver(struct DSBuffer *dsBuffer) { | |
| printf("fwver: %.*s\n", 19, dsBuffer->fw_ver); | |
| } | |
| void print_vdslprf(struct DSBuffer *dsBuffer) { | |
| printf("vdsl profile: %s\n", dsBuffer->profile); | |
| } | |
| void print_vdslstate(struct DSBuffer *dsBuffer) { | |
| printf("vdsl state: %s\n", dsBuffer->state); | |
| } | |
| int decryptDslBuffer( | |
| uint8_t *encryptedBuffer, | |
| struct DSBuffer *dsBuffer, | |
| const struct ether_addr *macAddr | |
| ) { | |
| const unsigned char magicref[4] = {0x20, 0x52, 0x05, 0x20}; | |
| if (memcmp((unsigned char *) encryptedBuffer, magicref, 4) != 0) { | |
| return -2; | |
| printf("Incorrect magic byte"); | |
| } | |
| uint8_t messageDigest[SHA_DIGEST_LENGTH]; | |
| uint8_t key[SHA_DIGEST_LENGTH * 2]; | |
| uint8_t iv[24]; | |
| memset(key, 0x0, 17); | |
| memset(iv, 0x0, 17); | |
| SHA1((uint8_t *) macAddr, ETH_ALEN, messageDigest); | |
| int i; | |
| int j = 0; | |
| for (i = 0; (j < SHA_DIGEST_LENGTH && i < 10); i += 2) { | |
| sprintf((char *) &key[i], "%02X", messageDigest[j]); | |
| j++; | |
| } | |
| // Use first 17 bytes of SHA1 as IV, 16th byte is null terminator | |
| memcpy(iv, key, 17); | |
| // printf("%s\n", iv); | |
| // printf("%s\n", key); | |
| memcpy(dsBuffer, encryptedBuffer, 116); | |
| struct AES_ctx aesCtx; | |
| AES_init_ctx_iv(&aesCtx, key, iv); | |
| // Skip first 4 bytes (magic bytes) | |
| AES_CBC_decrypt_buffer(&aesCtx, ((uint8_t *) dsBuffer) + sizeof(magicref), 112); | |
| return 0; | |
| } | |
| _Noreturn void handleSocket(char *macAddress) { | |
| int sock; /* Socket */ | |
| struct sockaddr_in broadcastAddr; /* Broadcast Address */ | |
| unsigned short broadcastPort; /* Port */ | |
| unsigned char recvString[MAXRECVSTRING + 1]; /* Buffer for received string */ | |
| size_t recvStringLen; /* Length of received string */ | |
| fd_set readfd; | |
| int ret; | |
| struct sockaddr_in client_addr; | |
| struct sockaddr_in server_addr; | |
| socklen_t addr_len; | |
| struct DSBuffer dslData; | |
| struct ether_addr macAddr; | |
| ether_aton_r(macAddress, &macAddr); | |
| broadcastPort = 4944; | |
| /* Create a best-effort datagram socket using UDP */ | |
| if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) | |
| printf("socket() failed"); | |
| /* Construct bind structure */ | |
| memset(&broadcastAddr, 0, sizeof(broadcastAddr)); /* Zero out structure */ | |
| broadcastAddr.sin_family = AF_INET; /* Internet address family */ | |
| broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ | |
| broadcastAddr.sin_port = htons(broadcastPort); /* Broadcast port */ | |
| /* Bind to the broadcast port */ | |
| if (bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr)) < 0) | |
| printf("bind() failed"); | |
| while (1) { | |
| FD_ZERO(&readfd); | |
| FD_SET(sock, &readfd); | |
| ret = select(sock + 1, &readfd, NULL, NULL, 0); | |
| if (ret > 0) { | |
| if (FD_ISSET(sock, &readfd)) { | |
| recvStringLen = recvfrom( | |
| sock, | |
| recvString, | |
| MAXRECVSTRING, | |
| 0, | |
| (struct sockaddr *) &client_addr, | |
| &addr_len | |
| ); | |
| if (recvStringLen != 116) { | |
| printf("Incorrect number of bytes recvd!"); | |
| continue; | |
| } | |
| printf( | |
| "Received UDP Datagram of correct size: using Key %s to decrypt contents\n", | |
| ether_ntoa(&macAddr) | |
| ); | |
| decryptDslBuffer(recvString, &dslData, &macAddr); | |
| // printf("Size of DSLBuffer: %lu\n", sizeof(struct DSBuffer)); | |
| assert(sizeof(struct DSBuffer) == 116); | |
| print_dsltype(&dslData); | |
| print_downspeed(&dslData); | |
| print_downspeed_in_mbps(&dslData); | |
| print_upspeed(&dslData); | |
| print_snrdown(&dslData); | |
| print_snrup(&dslData); | |
| print_wan(&dslData); | |
| print_timestamp(&dslData); | |
| print_fwver(&dslData); | |
| print_vdslprf(&dslData); | |
| print_vdslstate(&dslData); | |
| printf("=================================================================\n"); | |
| } | |
| } | |
| } | |
| } | |
| int main(int argn, char *argv[]) { | |
| if (argn != 2) { | |
| printf("Usage:\n"); | |
| printf("%s <mac address of Vigor 130 DSL Modem>\n", argv[0]); | |
| printf("e.g. %s aa:bb:cc:dd:ee:ff\n", argv[0]); | |
| return 1; | |
| } | |
| handleSocket(argv[1]); | |
| } |
Hi Matthew
Just a nudge given that this is an Internet facing device I wouldn’t suggest you share MAC address here.
Just a few questions
How did you obtain the above packet capture?
Have you tested with my original code with your PCAP at all?
I used netcat to rebroadcast my capture, let me see if I can dig out the command for you.
What encryption library are you using with Python? I recall having to faff a lot with the format of the IV
Just as a heads it will be unlikely it will just work verbatim with the newer vigors without some pain
- 130 had an ADSL model, is the 166 VDSL only, I wouldn’t be surprised if the 166 just left these fields unpopulated, but I think it’s unlikely
- hopefully newer models now use a better and more secure encryption routine
Would be happy to help if you share your code so far
Hi @sgarwood, thanks, all good now, I hadn't originally tested with your code as I don't tend to code in C... it was the endian of the MAC address that caught me out. Getting the C to build was a bit annoying too as I tried to compile in Visual Studio and then found it uses Linux headers so dusted down my Raspberry Pi and learnt about needing to apt-get install libssl-dev and using gcc -Ilib/tiny-AES-c -Wall -Wextra -pedantic -Werror -s -o dsl_status lib/tiny-AES-c/aes.c main.c -lcrypto.
I now have a Python version that should be cross-platform compatible: https://github.com/Matthew1471/DrayTek-Tools
I also made a few changes to the C file. Some of the comments in the gist were a little misleading, it's not the first 16 bytes of the SHA1 being used and I think you said elsewhere it's 10 bytes of the SHA1 digest but it's actually only 5 bytes - which in hex is 10 characters. I can provide an updated copy if that's helpful?
I presume you found the info from decompilation (I tried that but struggled with tooling for ARM). I also am curious how the router knows if it's decrypted correct data rather than garbage - and I suspect looking for a known good set of bytes probably enables that..
I'm going to experiment with the security of the protocol next as I am curious how much validation the router does of the input.
Thanks again for finding out the encryption method!
RE: MAC Address, I am not using the device as a Router, purely a modem (as in establishing a PPPoE tunnel to my ISP).. so only me and my ISP will see data for and from that MAC address (hopefully) turns out I'm not even using the device, it was from a Vigor166 and I am using my Vigor167 😄... I've committed to the respository aa:bb:cc:dd:ee:ff examples as it probably helps readability rather than seeing a random MAC address anyway.
Glad you got there in the end.
Nice work on the Python port!
My bad WRT the misleading comments. Given your issues with getting this to run I think I’d say leave this as an archive and I’d suggest anyone who might in interested in this use the Python implementation, it’s a much more accessible ecosystem.
My original intention in doing all this was to get build a PfSense plugin to display the modem data in the UI like the Draytek routers have. Should be a lot easier to implement in Python and more secure, if I have time I will have a go at trying this over Christmas break.
Just thinking as well one of my other ideas was to log this data into a time series DB like InfluxDB to monitor it over time, with Python that will be a lot easier.
I’ve emailed you regarding some of your other questions.
Added some validation as well as other features (support for signal handling, negative values, key debugging printing, DSL type detection, buffer overflow security features and allowing multiple instances) and improvements (also published at https://github.com/Matthew1471/DrayTek-Tools/blob/main/C/):
/*
* This file is part of DrayTek-Tools <https://github.com/Matthew1471/DrayTek-Tools>
* Copyright (c) 2024 Matthew1471!
*
* 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, version 3.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
// Adapted from https://gist.github.com/sgarwood/c60883ad2921893d1e9def4bd22b0728
#include <arpa/inet.h> // inet_* functions (includes netinet/in.h).
#include <assert.h> // assert() function.
#include <errno.h> // Standard error number types.
#include <net/ethernet.h> // Ethernet definitions and structures.
#include <netinet/ether.h> // ether_* functions (includes net/ethernet.h).
#include <netinet/in.h> // sockaddr_in type (includes sys/socket.h).
#include <openssl/sha.h> // SHA1() function ("apt-get install libssl-dev" if missing).
#include <signal.h> // signal() function (includes unistd.h).
#include <stdio.h> // printf() and fprintf() functions.
#include <stdlib.h> // exit() function.
#include <string.h> // memset() and strerror() functions.
#include <sys/select.h> // select() function.
#include <sys/socket.h> // socket() function.
#include <sys/types.h> // System call data types.
#include <unistd.h> // close() function.
#include "lib/tiny-AES-c/aes.h" // AES decryption functions.
#define DEBUG 0 // Whether to print debugging information.
#define DSL_STATUS_LENGTH 116 // The length of a DSL Status message in bytes.
// Used to signal when the program should exit.
volatile sig_atomic_t ShouldStop = 0;
// Define the DslType enumeration.
enum DslType {
ADSL = 1,
VDSL = 6
};
// Define the DslStatus structure.
struct DslStatus {
unsigned char protocol_identifier[4]; // 0
int32_t dsl_upload_speed; // 4
int32_t dsl_download_speed; // 8
int32_t adsl_tx_cells; // 12
int32_t adsl_rx_cells; // 16
int32_t adsl_tx_crc_errors; // 20
int32_t adsl_rx_crc_errors; // 24
enum DslType dsl_type; // 28
int32_t timestamp; // 32
int32_t vdsl_snr_upload; // 36
int32_t vdsl_snr_download; // 40
int32_t adsl_loop_att; // 44
int32_t adsl_snr_margin; // 48
char modem_firmware_version[20]; // 52
char running_mode[18]; // 72 VDSL Profile or ADSL mode
char state[26]; // 90
// 116 Total Bytes
};
// Function to optionally output the MAC address and decryption key.
void print_debug_info(const struct ether_addr *mac_address, const uint8_t *key, uint8_t key_length) {
printf("\nMAC Address: %02X%02X%02X%02X%02X%02X\n",
mac_address->ether_addr_octet[0],
mac_address->ether_addr_octet[1],
mac_address->ether_addr_octet[2],
mac_address->ether_addr_octet[3],
mac_address->ether_addr_octet[4],
mac_address->ether_addr_octet[5]);
printf("Key/IV: %s\n", key);
for (uint8_t count = 0; count < key_length; count++) {
printf(" Key #%d = %c = %02X\n", count, key[count], key[count]);
}
}
void print_dsl_status(enum DslType dsl_type, const struct DslStatus* dsl_status_data) {
printf("\n");
if (DEBUG) {
printf(" DSL Status Protocol Identifier: 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
dsl_status_data->protocol_identifier[0],
dsl_status_data->protocol_identifier[1],
dsl_status_data->protocol_identifier[2],
dsl_status_data->protocol_identifier[3]
);
}
printf(" DSL Upload Speed: %d bps", (int32_t)ntohl(dsl_status_data->dsl_upload_speed));
printf(" (%d Mbps)\n", (int32_t)ntohl(dsl_status_data->dsl_upload_speed) / 1000000);
printf(" DSL Download Speed: %d bps", (int32_t)ntohl(dsl_status_data->dsl_download_speed));
printf(" (%d Mbps)\n", (int32_t)ntohl(dsl_status_data->dsl_download_speed) / 1000000);
if (DEBUG || dsl_type == ADSL) {
printf(" ADSL TX Cells: %d\n", (int32_t)ntohl(dsl_status_data->adsl_tx_cells));
printf(" ADSL RX Cells: %d\n", (int32_t)ntohl(dsl_status_data->adsl_rx_cells));
printf(" ADSL TX CRC Errors: %d\n", (int32_t)ntohl(dsl_status_data->adsl_tx_crc_errors));
printf(" ADSL RX CRC Errors: %d\n", (int32_t)ntohl(dsl_status_data->adsl_rx_crc_errors));
}
printf(" DSL Type: ");
switch (dsl_type) {
case ADSL:
printf("ADSL");
break;
case VDSL:
printf("VDSL");
break;
default:
printf("Unknown");
}
printf("\n");
printf(" Timestamp: %d\n", (int32_t)ntohl(dsl_status_data->timestamp));
if (DEBUG || dsl_type == VDSL) {
printf(" VDSL SNR Upload: %d\n", (int32_t)ntohl(dsl_status_data->vdsl_snr_upload));
printf(" VDSL SNR Download: %d\n", (int32_t)ntohl(dsl_status_data->vdsl_snr_download));
}
if (DEBUG || dsl_type == ADSL) {
printf(" ADSL Loop Attenuation: %d\n", (int32_t)ntohl(dsl_status_data->adsl_loop_att));
printf(" ADSL SNR Margin: %d\n", (int32_t)ntohl(dsl_status_data->adsl_snr_margin));
}
printf(" Modem Firmware Version: %.*s\n", 20, dsl_status_data->modem_firmware_version);
printf(" Running Mode: %.*s\n", 18, dsl_status_data->running_mode);
printf(" State: %.*s\n\n", 26, dsl_status_data->state);
}
// Decrypts DSL Status broadcast bytes into the DslStatus structure.
int decrypt_dsl_status(
const struct ether_addr *mac_address,
uint8_t *encrypted_buffer,
struct DslStatus *dsl_status) {
// The protocol identifies itself with these bytes.
const unsigned char signature_bytes[4] = {0x20, 0x52, 0x05, 0x20};
// Check the payload is a DSL Status message.
if (memcmp((unsigned char *) encrypted_buffer, signature_bytes, 4) != 0) {
fprintf(stderr, "Error: Incorrect protocol signature bytes.\n");
return -EPROTO;
}
// The encryption key is the first 5 bytes from the SHA-1 digest.
uint8_t message_digest[SHA_DIGEST_LENGTH];
SHA1((uint8_t *) mac_address, ETH_ALEN, message_digest);
// Create a 17 byte array and set all positions to null (we will populate only 10 bytes).
uint8_t key[17];
memset(key, 0x0, 17);
// Get the uppercase hexadecimal characters of the digest (10 characters).
int current_digest_byte = 0;
for (uint8_t current_key_position = 0; current_key_position < 10; current_key_position += 2) {
// Fill 2 positions of the key with the 2 hex characters from a single digest byte.
// We will do this for only 10 bytes in the key, the 6 remaining bytes remain null.
sprintf((char *) &key[current_key_position], "%02X", message_digest[current_digest_byte]);
current_digest_byte++;
}
// Debugging.
if (DEBUG) {
print_debug_info(mac_address, key, sizeof(key) / sizeof(key[0]));
}
// Copy the encrypted_buffer to the dsl_status prior to decryption.
memcpy(dsl_status, encrypted_buffer, DSL_STATUS_LENGTH);
// Initialise the AES decrypter (the iv/key has to be 16 bytes for AES128).
struct AES_ctx aesCtx;
AES_init_ctx_iv(&aesCtx, key, key);
// Decrypt the payload (skipping the first 4 signature bytes).
AES_CBC_decrypt_buffer(&aesCtx, ((uint8_t *) dsl_status) + sizeof(signature_bytes), DSL_STATUS_LENGTH - sizeof(signature_bytes));
// Return success.
return 0;
}
void handle_sigint(int sig) {
// This line does nothing but prevents the unused parameter warning.
(void)sig;
// Set the flag to stop the loop.
ShouldStop = 1;
}
void receive_data(char *mac_address_string) {
// Get the MAC address string in bytes.
struct ether_addr mac_address;
if (ether_aton_r(mac_address_string, &mac_address) == NULL) {
fprintf(stderr, "Error: Invalid MAC address format.\n");
exit(EXIT_FAILURE);
}
// Create an IPv4 datagram socket using UDP.
int sock;
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// Permit multiple receiver threads listening.
int opt = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
fprintf(stderr, "setsockopt() failed: %s\n", strerror(errno));
close(sock);
exit(EXIT_FAILURE);
}
// Construct bind structure.
struct sockaddr_in broadcast_address;
memset(&broadcast_address, 0, sizeof(broadcast_address)); // Zero out structure.
broadcast_address.sin_family = AF_INET; // Internet address family.
broadcast_address.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface.
broadcast_address.sin_port = htons(4944); // Broadcast port.
// Bind to the broadcast port.
if (bind(sock, (struct sockaddr *) &broadcast_address, sizeof(broadcast_address)) < 0) {
fprintf(stderr, "bind() failed: %s\n", strerror(errno));
close(sock);
exit(EXIT_FAILURE);
}
// Register the signal handler.
signal(SIGINT, handle_sigint);
// Now listening for messages until the program is exited.
while (!ShouldStop) {
fd_set socket_fd_set;
FD_ZERO(&socket_fd_set);
FD_SET(sock, &socket_fd_set);
// Buffer for received string.
unsigned char received_data[DSL_STATUS_LENGTH + 1];
// Is a socket ready for reading?
if (select(sock + 1, &socket_fd_set, NULL, NULL, 0) > 0) {
if (FD_ISSET(sock, &socket_fd_set)) {
// The client address.
struct sockaddr_in client_address;
socklen_t address_length = sizeof(client_address);
// Attempt to receive a broadcast packet.
uint8_t received_data_length = recvfrom(
sock,
received_data,
DSL_STATUS_LENGTH,
0,
(struct sockaddr *) &client_address,
&address_length
);
// Check to see if this would be the right length for a DSL Status message.
if (received_data_length != DSL_STATUS_LENGTH) {
// Wait for another message as this is not a DSL Status message.
continue;
}
// Notify user a message has been received.
printf(
"Received UDP Datagram from %s of correct size; using MAC Address %s to decrypt contents:\n",
inet_ntoa(client_address.sin_addr),
ether_ntoa(&mac_address)
);
// Perform the decryption.
struct DslStatus dsl_status_data;
if (decrypt_dsl_status(&mac_address, received_data, &dsl_status_data) == 0) {
// printf("Size of DSL Status Data: %lu\n", sizeof(dsl_status_data));
assert(sizeof(dsl_status_data) == DSL_STATUS_LENGTH);
// Convert the dsl_type byte to a DslType enum.
enum DslType dsl_type = (enum DslType)ntohl(dsl_status_data.dsl_type);
// Check the DSL type is valid.
if (dsl_type != ADSL && dsl_type != VDSL) {
// Notify the user the decrypted payload failed validation.
printf(" * Message failed DSL Type validation, check decryption key.\n\n");
// Wait for another message as this is not a valid DSL Status message.
continue;
}
// Output to console.
print_dsl_status(dsl_type, &dsl_status_data);
} else {
// Notify the user of decryption failure.
printf(" * Message failed to decrypt, check decryption key.\n\n");
}
}
}
}
// Ensure the socket is closed properly.
close(sock);
}
int main(int argc, char *argv[]) {
// Check whether the user has supplied a source MAC address.
if (argc != 2) {
printf("Usage:\n");
printf(" %s <MAC Address of Vigor™ DSL Modem>\n\n", argv[0]);
printf("e.g. %s aa:bb:cc:dd:ee:ff\n", argv[0]);
return -EINVAL;
}
// Start listening for data.
receive_data(argv[1]);
// Notify the user that the program has completed successfully.
printf("\nThe program completed successfully.\n");
}
Hi @sgarwood, do you have any Vigor 130 sample data please? I'm attempting to convert this to Python (for Vigor 166/167) and I can't get a decent decrypt working and need to work out if I've coded it wrong or if they're different systems.
MAC:
14:49:bc:57:51:10UDP Payload (including 4 magic bytes):