├── assets ├── RELATION.png ├── UART_pin.png ├── ODU_STATS_SCRIPT.png ├── FIND_ODU_LOCAL_LINK.png ├── ODU_Login_page_image.png ├── ODU_STATS_LIVE_SCRIPT.png ├── ODU_ipv6_address_fetch.png └── IDU_extroot_fstab_config.png ├── .gitignore ├── instructions ├── JAF-IDU-Reset-Via-SSH.md ├── JAF-IDU-UART-Access.md ├── JAF-ODU-Access-Via-The-IDU.md ├── JAF-ODU-SSH-Access-Via-ADB.md ├── JAF-ODU-Access-Via-Bluetooth.md ├── JAF-IDU-UBOOT-Access.md ├── JAF-IDU-Root-Access.md ├── Understanding-Workings-Of-TR069.md ├── List-OF-IDU's-and-ODU's.md └── JAF-IDU-LuCI-Install-Guide.md ├── General-Troubleshooting.md ├── scripts ├── mac2ipv6.sh ├── tg.sh ├── find_oduv6.sh ├── odu_stats.sh ├── realation.py ├── odu_stats_live.sh ├── opensync_disabler.sh ├── breeze.sh └── enableRootSSH.sh ├── README.md └── Scripts-and-Hacks.md /assets/RELATION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/RELATION.png -------------------------------------------------------------------------------- /assets/UART_pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/UART_pin.png -------------------------------------------------------------------------------- /assets/ODU_STATS_SCRIPT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/ODU_STATS_SCRIPT.png -------------------------------------------------------------------------------- /assets/FIND_ODU_LOCAL_LINK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/FIND_ODU_LOCAL_LINK.png -------------------------------------------------------------------------------- /assets/ODU_Login_page_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/ODU_Login_page_image.png -------------------------------------------------------------------------------- /assets/ODU_STATS_LIVE_SCRIPT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/ODU_STATS_LIVE_SCRIPT.png -------------------------------------------------------------------------------- /assets/ODU_ipv6_address_fetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/ODU_ipv6_address_fetch.png -------------------------------------------------------------------------------- /assets/IDU_extroot_fstab_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JFC-Group/AF-Customisation/HEAD/assets/IDU_extroot_fstab_config.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore specific backup and encrypted files 2 | backup-*_enc.tar.gz 3 | encrypted_backup_mod.tar.gz 4 | backup_mod.tar.gz 5 | dec_backup_og.tar.gz 6 | 7 | # Ignore extracted backup directories 8 | extracted_backup/ 9 | 10 | # Ignore obsidian files 11 | .obsidian -------------------------------------------------------------------------------- /instructions/JAF-IDU-Reset-Via-SSH.md: -------------------------------------------------------------------------------- 1 | # Resetting the Router via SSH 2 | 3 | _Disclaimer: This is ONLY for educational purposes, No one is responsible for any type of damage. So be aware._ 4 | 5 | - Log into the router via SSH and run the below command to initiate the reset process. 6 | 7 | ```shell 8 | jffs2reset -r -y 9 | ``` 10 | -------------------------------------------------------------------------------- /General-Troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting E-sim Profile Issues 2 | 3 | ## Common Issues and Solutions 4 | 5 | ### 1. QR Code Scanning Issues 6 | 7 | #### Problem: Extra Characters in EID 8 | **Symptoms**: 9 | - "JPW Parameter mismatch - EID" error 10 | - QR code scan fails or reads incorrect EID 11 | - Extra control characters (like `␌`) in the QR code 12 | - Malformed XML in the QR code 13 | 14 | **Solution:** 15 | 1. Create a new QR code with clean XML format 16 | 2. Ensure no extra characters before or after the EID 17 | 3. Verify the XML structure is correct: 18 | -------------------------------------------------------------------------------- /scripts/mac2ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Convert a MAC address (e.g., 00:06:AE:A3:AE:90) to IPv6 link-local (EUI-64) 4 | mac="$1" 5 | 6 | if [[ -z "$mac" ]]; then 7 | echo "Usage: $0 " 8 | exit 1 9 | fi 10 | 11 | # Ensure MAC is lowercase and colon-separated 12 | mac=$(echo "$mac" | tr '[:upper:]' '[:lower:]') 13 | 14 | IFS=':' read -r -a octets <<< "$mac" 15 | 16 | # Flip the 7th bit of the first octet 17 | first_octet=$(( 0x${octets[0]} ^ 0x02 )) 18 | first_octet_hex=$(printf "%02x" $first_octet) 19 | 20 | # Construct EUI-64 21 | eui64="${first_octet_hex}${octets[1]}:${octets[2]}ff:fe${octets[3]}:${octets[4]}${octets[5]}" 22 | 23 | # Output full link-local IPv6 address 24 | echo "fe80::${eui64}" 25 | 26 | -------------------------------------------------------------------------------- /scripts/tg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Telegram Bot API credentials 4 | BOT_TOKEN="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 5 | CHAT_ID="XXXXXXXXXXXXXXX" 6 | FILE="$1" 7 | TEMP_FILE="cp-${FILE}" 8 | 9 | # Infinite loop to send the file every 30 minutes 10 | while true; do 11 | cp "$FILE" "$TEMP_FILE" 12 | echo "Sending ${FILE} to Telegram..." 13 | 14 | echo "curl -k -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendDocument" -F chat_id="${CHAT_ID}" -F document=@"${TEMP_FILE}"" 15 | curl -k -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendDocument" \ 16 | -F chat_id="${CHAT_ID}" \ 17 | -F document=@"${TEMP_FILE}" \ 18 | -F caption="📊 $(date)" 19 | 20 | echo "File sent. Waiting 30 minutes before next send." 21 | 22 | # Wait for 1800 seconds (30 minutes) 23 | sleep 1800 24 | done 25 | -------------------------------------------------------------------------------- /instructions/JAF-IDU-UART-Access.md: -------------------------------------------------------------------------------- 1 | # JAF IDU UART Access 2 | 3 | _Disclaimer: This is ONLY for educational purposes, No one is responsible for any type of damage. So be aware._ 4 | 5 | ## Steps 6 | 7 | 1. Strip apart the IDU and find the 4 uart pins; usually marked on most models of IDU. Some models have pins already soldered onto the pads so you don't have to. 8 | ![UART pin](../assets/UART_pin.png) 9 | 10 | 2. Only connect Rx , Tx and GND ; do not connect 3.3v pin to your usb-to-ttl or whatever device you are using as a serial converter as it may fry your IDU. 11 | 12 | 3. Install putty if you dont have a serial terminal already. use the configs below and connect the IDU to your serial converter. 13 | 14 | 4. power on the IDU and see text starts flowing on your terminal. If you see garbled text then check your connections or try reversing the Rx Tx pins. 15 | 16 | ## Configs 🐮 17 | 18 | BaudRate: 115200 19 | DataBits: 8 20 | StopBits: 1 21 | Parity: None 22 | FlowControl: None 23 | 24 | ## Note 25 | 26 | This has been tested on JIDU6801 and if you still encounter garbled text then maybe your model has a different baud rate; try using other common baud rates. Also your usb to ttl might be having issues so do check that. 27 | -------------------------------------------------------------------------------- /instructions/JAF-ODU-Access-Via-The-IDU.md: -------------------------------------------------------------------------------- 1 | # Accessing the ODU WEB-UI from local network 2 | 3 | _Disclaimer: This is ONLY for educational purposes, No one is responsible for any type of damage. So be aware._ 4 | 5 | 1. Fetch the local link ip of the ODU using this command: 6 | 7 | ```shell 8 | ovsdb-client transact '[ 9 | "Open_vSwitch", 10 | { 11 | "op": "select", 12 | "table": "IPv6_Neighbors", 13 | "where": [["if_name", "==", "eth1"]], 14 | "columns": ["address"] 15 | } 16 | ]' 17 | ``` 18 | 19 | ![ODU ipv6 address fetch](../assets/ODU_ipv6_address_fetch.png) 20 | 21 | _NOTE: If you couldn't get the local link or there is no link present in the output, utilize the mac2ipv6 generator script. [mac2ipv6](../scripts/mac2ipv6.sh)_ 22 | 23 | 24 | 25 | 2. Start a SSH tunnel from any local device: 26 | 27 | ```shell 28 | ssh -L 8443:[]:443 root@192.168.31.1 29 | ``` 30 | 31 | * Substitute the local link ip with what you get as output from previous command. For example: 32 | 33 | ```shell 34 | ssh -L 8443:[fe80::9632:51ff:fe04:c136%eth1]:443 root@192.168.31.1 35 | ``` 36 | 37 | 3. Access ODU via `https://localhost:8443`: 38 | 39 | ![ODU Login page image](../assets/ODU_Login_page_image.png) 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Breezing through the AF 2 | 3 | ## Disclaimer 4 | 5 | *This is for educational purposes ONLY. No one is responsible for any type of damage.* 6 | 7 | ## Table Of Contents 8 | 9 | | 🔢 No. | 📄 Title | 🔗 Link | 10 | | :----: | ---------------------------- | :-----------------------------------------------------: | 11 | | 1 | JAF IDU Root Access | [Open](instructions/JAF-IDU-Root-Access.md) | 12 | | 2 | JAF IDU UART Access | [Open](instructions/JAF-IDU-UART-Access.md) | 13 | | 3 | JAF IDU UBOOT Access | [Open](instructions/JAF-IDU-UBOOT-Access.md) | 14 | | 4 | JAF IDU Reset Via SSH | [Open](instructions/JAF-IDU-Reset-Via-SSH.md) | 15 | | 5 | JAF IDU LuCI Install Guide | [Open](instructions/JAF-IDU-LuCI-Install-Guide.md) | 16 | | 6 | JAF ODU Access Via The IDU | [Open](instructions/JAF-ODU-Access-Via-The-IDU.md) | 17 | | 7 | JAF ODU Access Via Bluetooth | [Open](instructions/JAF-ODU-Access-Via-Bluetooth.md) | 18 | | 8 | JAF ODU SSH Access Via ADB | [Open](instructions/JAF-ODU-SSH-Access-Via-ADB.md) | 19 | | 9 | List of IDUs and ODUs | [Open](instructions/List-OF-IDU's-and-ODU's.md) | 20 | | 10 | Understand Tr069 | [Open](instructions/Understanding-Workings-Of-TR069.md) | 21 | 22 | ## Miscellaneous 23 | ### 💻[Scripts-and-Hacks](Scripts-and-Hacks.md) 24 | 25 | ### ⛏️[General-Troubleshooting](General-Troubleshooting.md) 26 | 27 | -------------------------------------------------------------------------------- /scripts/find_oduv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | 3 | # Check for MAC argument 4 | if [ $# -ne 1 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | mac=$(echo "$1" | tr 'A-F' 'a-f') 10 | 11 | # Validate MAC format (12 hex digits, no separators) 12 | case "$mac" in 13 | [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) ;; 14 | *) 15 | echo "Invalid MAC address format. Must be 12 hex digits, no colons or dashes." 16 | exit 1 17 | ;; 18 | esac 19 | 20 | # Split into bytes 21 | m1=${mac:0:2} 22 | m2=${mac:2:2} 23 | m3=${mac:4:2} 24 | m4=${mac:6:2} 25 | m5=${mac:8:2} 26 | m6=${mac:10:2} 27 | 28 | # Flip 7th bit of first byte 29 | flip_byte=$(printf "%02x" $((0x$m1 ^ 0x02))) 30 | 31 | # Construct link-local IPv6 (EUI-64) 32 | ipv6="fe80::${flip_byte}${m2}:${m3}ff:fe${m4}:${m5}${m6}" 33 | 34 | echo "[*] Generated IPv6 from MAC: $ipv6" 35 | 36 | # Try interfaces eth0 to eth5 37 | for i in 0 1 2 3 4 5; do 38 | iface="eth$i" 39 | echo "[*] Trying interface: $iface" 40 | 41 | result=$(curl -g -6 -v --interface "$iface" "https://[$ipv6]/" --insecure --max-time 5 2>&1) 42 | code=$(echo "$result" | sed -n 's/.*< HTTP\/[^ ]* \([0-9][0-9][0-9]\).*/\1/p') 43 | 44 | case "$code" in 45 | ''|*[!0-9]*) code=0 ;; 46 | esac 47 | 48 | if [ "$code" -ge 200 ] 2>/dev/null && [ "$code" -lt 400 ] 2>/dev/null; then 49 | echo "" 50 | echo "[+] SUCCESS on interface: $iface (HTTP $code)" 51 | echo "------------------------------------------------------------" 52 | echo "✅ ODU Web UI is accessible at:" 53 | echo " https://[$ipv6%$iface]:443" 54 | echo "" 55 | echo "🔐 To create an SSH tunnel from your local device, run:" 56 | echo " ssh -L 8443:[$ipv6%$iface]:443 root@192.168.31.1" 57 | echo "Then access it at https://localhost:8443" 58 | echo "------------------------------------------------------------" 59 | exit 0 60 | else 61 | echo "[-] Failed on $iface (HTTP $code)" 62 | fi 63 | done 64 | 65 | echo "[!] Could not reach ODU on any interface." 66 | exit 1 67 | -------------------------------------------------------------------------------- /instructions/JAF-ODU-SSH-Access-Via-ADB.md: -------------------------------------------------------------------------------- 1 | # JAF ODU SSH Access Via ADB 2 | 3 | _Disclaimer: This is ONLY for educational purposes, No one is responsible for any type of damage. So be aware._ 4 | 5 | _NOTE: Works only for the models supporting ADB access._ 6 | 7 | Credits: [@sumishimii](https://github.com/sumishimii/) 8 | 9 | ## Prerequisites 10 | 11 | - [ADB](https://developer.android.com/tools/releases/platform-tools) installed on your PC. 12 | - Clone the repo: 13 | 14 | ## Overview 15 | 16 | The sshd binary exists on the JAF ODU at `/usr/sbin/sshd`. However, the root filesystem is read-only, which prevents modifying the sshd config directly or changing the root password, that's why I used SSH key-based auth to get access to the ODU. 17 | 18 | > ⚠️ **This method is not persistent and you'll lose ssh connection if the ODU is restarted.** ⚠️ 19 | 20 | ## Steps to Enable SSH 21 | 22 | ### Step 1: Generate an SSH key pair on your PC 23 | 24 | > You can leave the passphrase empty if you want. 25 | 26 | - On Linux/MacOS: 27 | 28 | ```bash 29 | ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa 30 | ``` 31 | 32 | - On Windows: 33 | 34 | ```cmd 35 | ssh-keygen -t rsa -b 2048 36 | ``` 37 | 38 | The `id_rsa.pub` file can be found at `%USERPROFILE%\.ssh\id_rsa.pub`. 39 | 40 | **Once the keys are generated, copy the content of id_rsa.pub to the authorized_keys file in `get-ssh` folder of the cloned repo.** 41 | 42 | ### Step 2: Push the get-ssh folder using adb 43 | 44 | Push the `get-ssh` folder of the cloned repo to the `/tmp` directory of the ODU using ADB. 45 | 46 | ```bash 47 | adb push get-ssh/ /tmp/ 48 | ``` 49 | 50 | ### Step 3: Run the `run.sh` script in adb shell 51 | 52 | ```bash 53 | adb shell 54 | ``` 55 | 56 | In adb shell run the command 57 | 58 | ```bash 59 | cd /tmp/get-ssh/ && chmod +x run.sh && ./run.sh 60 | ``` 61 | 62 | You can now SSH into the ODU either directly from it's IPv4 address if you are in (Router Mode/Bridge Mode/Connected to ODU directly) OR instead a better way to access the ODU ssh would be using SSH Tunnel which we use for accessing the ODU WEB-UI. Just change the destination ports from 443 to 22 and change 8443 to any free port on your (PC/local device) being used to access the ODU. 63 | 64 | After establishing a SSH tunnel, proceed with the below command to access the ODU. 65 | 66 | ```bash 67 | ssh root@localhost -P 68 | ``` 69 | -------------------------------------------------------------------------------- /scripts/odu_stats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Site and API URLs 4 | BASE_URL="https://[fe80::9632:51ff:fe04:c136%eth1]" 5 | LOGIN_URL="$BASE_URL/auth.fcgi" 6 | DATA_URL="$BASE_URL/restful/lte/cellular_info_nr5g_sa" 7 | 8 | # Login credentials 9 | USERNAME="Admin" 10 | PASSWORD="\$2a\$11\$W8/KspexdthEsSV3kVygMO1JdXShMXyf9UPLXoYF79gd6cfwwXSNC" 11 | 12 | # CSV file path 13 | CSV_FILE="statistics.csv" 14 | 15 | # Check if CSV file exists, if not, add header 16 | if [ ! -f "$CSV_FILE" ]; then 17 | echo "timestamp,pci,rsrp,rsrq,sinr,band,bandwidth,dl_arfcn,ul_arfcn,cell_id,tac,signal_strength" > "$CSV_FILE" 18 | fi 19 | 20 | # Function to log in and retrieve UID 21 | get_uid() { 22 | response=$(curl -ks -X POST "$LOGIN_URL" \ 23 | -H "Content-Type: application/json" \ 24 | -d "{\"AuthCmd\":\"Login\",\"UserName\":\"$USERNAME\",\"UserPW\":\"$PASSWORD\"}") 25 | 26 | echo "$response" | jq -r '.Result[0].Login' 27 | } 28 | 29 | # Get the session UID 30 | UID=$(get_uid) 31 | if [ -z "$UID" ] || [ "$UID" == "null" ]; then 32 | echo "Login failed. Exiting..." 33 | exit 1 34 | fi 35 | echo "Login successful! UID: $UID" 36 | 37 | # Refresh UID every 30 minutes 38 | NEXT_REFRESH=$((SECONDS + 1800)) 39 | 40 | # Function to fetch data and save to CSV 41 | fetch_data() { 42 | timestamp=$(date '+%Y-%m-%d %H:%M:%S') 43 | 44 | response=$(curl -ks -X GET "$DATA_URL" \ 45 | -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \ 46 | -H "Accept: application/json, text/plain, */*" \ 47 | -H "Cookie: Secure; LANGUAGE=1; expert=true; UID=$UID; FIRST_LOGIN_FLAG=0; privilege=0; login_block=false") 48 | 49 | # Extract necessary fields 50 | csv_row=$(echo "$response" | jq -r --arg ts "$timestamp" '[ $ts, .Result.pci, .Result.rsrp, .Result.rsrq, .Result.sinr, .Result.band, .Result.bandwidth, .Result.dl_arfcn, .Result.ul_arfcn, .Result.cell_id, .Result.tac, .Result.signal_strength ] | @csv') 51 | 52 | echo "$csv_row" >> "$CSV_FILE" 53 | echo "Data saved: $csv_row" 54 | } 55 | 56 | # Infinite loop to fetch data every 5 seconds 57 | while true; do 58 | # Refresh UID every 30 minutes 59 | if [ "$SECONDS" -ge "$NEXT_REFRESH" ]; then 60 | echo "Refreshing UID..." 61 | UID=$(get_uid) 62 | if [ -z "$UID" ] || [ "$UID" == "null" ]; then 63 | echo "Re-login failed. Retrying in 10 seconds..." 64 | sleep 10 65 | else 66 | echo "Re-login successful! New UID: $UID" 67 | NEXT_REFRESH=$((SECONDS + 1800)) # Schedule next refresh 68 | fi 69 | fi 70 | 71 | fetch_data 72 | sleep 5 73 | done 74 | -------------------------------------------------------------------------------- /scripts/realation.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import matplotlib.dates as mdates 5 | from matplotlib.patches import Patch 6 | 7 | # Load CSV and parse the timestamp column 8 | df = pd.read_csv("statistics.csv", parse_dates=["timestamp"]) 9 | 10 | # Convert relevant columns to numeric if needed 11 | df["rsrp"] = pd.to_numeric(df["rsrp"], errors='coerce') 12 | df["sinr"] = pd.to_numeric(df["sinr"], errors='coerce') 13 | 14 | # Set timestamp as index 15 | df.set_index("timestamp", inplace=True) 16 | 17 | # Resample data per hour: 18 | # - For continuous metrics, use the mean. 19 | # - For PCI (a categorical value with little variation), take the first value in each period. 20 | df_hourly = pd.DataFrame({ 21 | 'rsrp': df['rsrp'].resample("1h").mean(), 22 | 'sinr': df['sinr'].resample("1h").mean(), 23 | 'pci': df['pci'].resample("1h").first() 24 | }) 25 | 26 | # Create a mapping for PCI values to colors using a pastel palette 27 | unique_pci = df_hourly['pci'].dropna().unique() 28 | pci_colors = sns.color_palette("pastel", len(unique_pci)) 29 | pci_color_map = dict(zip(unique_pci, pci_colors)) 30 | 31 | # Create the plot with two y-axes 32 | fig, ax1 = plt.subplots(figsize=(14, 6)) 33 | ax2 = ax1.twinx() 34 | 35 | # Shade the background for each hourly interval based on the PCI value 36 | for timestamp, pci_value in df_hourly['pci'].items(): 37 | if pd.notnull(pci_value): 38 | start = timestamp 39 | end = start + pd.Timedelta(hours=1) 40 | ax1.axvspan(start, end, color=pci_color_map[pci_value], alpha=0.15) 41 | 42 | # Plot the RSRP (primary y-axis) and SINR (secondary y-axis) 43 | sns.lineplot(ax=ax1, data=df_hourly, x=df_hourly.index, y="rsrp", 44 | label="RSRP (dBm)", linewidth=2.5, color="royalblue") 45 | sns.lineplot(ax=ax2, data=df_hourly, x=df_hourly.index, y="sinr", 46 | label="SINR (dB)", linewidth=2.5, color="darkorange") 47 | 48 | # Configure the x-axis: tick marks every 60 minutes with date & time formatting 49 | locator = mdates.MinuteLocator(interval=480) 50 | formatter = mdates.DateFormatter("%Y-%m-%d %H:%M") 51 | ax1.xaxis.set_major_locator(locator) 52 | ax1.xaxis.set_major_formatter(formatter) 53 | plt.setp(ax1.get_xticklabels(), rotation=45) 54 | 55 | # Set axis labels and title 56 | ax1.set_xlabel("Time", fontsize=12) 57 | ax1.set_ylabel("RSRP (dBm)", fontsize=12) 58 | ax2.set_ylabel("SINR (dB)", fontsize=12) 59 | plt.title("Hourly Variation of Signal Strength (RSRP) & SINR with PCI Shading", fontsize=14, fontweight="bold") 60 | 61 | # Create legends: 62 | # 1. Get the legend for the line plots. 63 | lines_handles, lines_labels = ax1.get_legend_handles_labels() 64 | legend_lines = ax1.legend(lines_handles, lines_labels, loc='upper left') 65 | 66 | # 2. Create a custom legend for PCI shading using patches. 67 | pci_patches = [Patch(facecolor=color, label=f"PCI: {pci}") for pci, color in pci_color_map.items()] 68 | legend_pci = ax1.legend(handles=pci_patches, loc='upper right', title="PCI Shading") 69 | 70 | # Ensure both legends are displayed. 71 | ax1.add_artist(legend_lines) 72 | 73 | plt.grid(True, linestyle="--", alpha=0.6) 74 | plt.tight_layout() 75 | plt.show() 76 | -------------------------------------------------------------------------------- /scripts/odu_stats_live.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ========== Dependency Checks ========== 4 | echo "[*] Checking dependencies..." 5 | 6 | # Check for Python 3 7 | if ! command -v python3 &> /dev/null; then 8 | echo "[!] Python3 is not installed. Install it first." 9 | exit 1 10 | fi 11 | 12 | # Check for 'bcrypt' module in Python 13 | if ! python3 -c "import bcrypt" &> /dev/null; then 14 | echo "[!] Python3 module 'bcrypt' not found. Installing..." 15 | if command -v pip3 &> /dev/null; then 16 | pip3 install bcrypt || { echo "[!] Failed to install bcrypt."; exit 1; } 17 | else 18 | echo "[!] pip3 is not available. Please install 'bcrypt' manually." 19 | exit 1 20 | fi 21 | fi 22 | 23 | # Check for jq 24 | if ! command -v jq &> /dev/null; then 25 | echo "[!] 'jq' is not installed. Please install it using your package manager." 26 | exit 1 27 | fi 28 | 29 | echo "[✓] All dependencies are satisfied." 30 | 31 | # Global variables 32 | SALT='$2a$11$W8/KspexdthEsSV3kVygMO' 33 | 34 | # Step 1: Get user input 35 | read -p "Enter host (e.g. localhost): " HOST 36 | read -p "Enter port (e.g. 8443): " PORT 37 | read -p "Enter username: " USERNAME 38 | read -s -p "Enter hashed password (leave blank to use text based pass): " HASHED_PW 39 | echo "" 40 | 41 | # Check if HASHED_PW is empty 42 | if [[ -z "$HASHED_PW" ]]; then 43 | read -s -p "Enter Admin password (text): " ASCII_PW 44 | echo "" 45 | 46 | read -p "Do you want to use a custom bcrypt salt? (y/N): " CHANGE_SALT 47 | if [[ "$CHANGE_SALT" =~ ^[Yy]$ ]]; then 48 | read -p "Enter bcrypt salt (must be 29 chars, e.g., \$2a\$11\$W8/KspexdthEsSV3kVygMO): " CUSTOM_SALT 49 | SALT="$CUSTOM_SALT" 50 | else 51 | echo "[*] Using default salt." 52 | fi 53 | 54 | # Generate bcrypt hash using Python 55 | HASHED_PW=$(python3 -c " 56 | import bcrypt 57 | password = b'$ASCII_PW' 58 | salt = b'$SALT' 59 | hashed = bcrypt.hashpw(password, salt) 60 | print(hashed.decode()) 61 | ") 62 | echo "[*] Password hashed with bcrypt." 63 | fi 64 | 65 | 66 | # Define URLs 67 | BASE_URL="https://${HOST}:${PORT}" 68 | LOGIN_URL="${BASE_URL}/auth.fcgi" 69 | STATS_URL="${BASE_URL}/restful/lte/cellular_info_nr5g_sa" 70 | 71 | # Step 2: Send login request 72 | echo "[*] Logging in..." 73 | 74 | RESPONSE=$(curl -sk -X POST "$LOGIN_URL" \ 75 | -H "Cookie: Secure; LANGUAGE=1; expert=true" \ 76 | -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \ 77 | --data-binary "{\"AuthCmd\":\"Login\",\"UserPW\":\"$HASHED_PW\",\"UserName\":\"$USERNAME\"}") 78 | 79 | # Step 3: Extract UID 80 | USER_ID=$(echo "$RESPONSE" | jq -r '.Result[0].Login') 81 | 82 | if [[ "$USER_ID" == "null" || -z "$USER_ID" ]]; then 83 | echo "[!] Login failed. Check your credentials or connection." 84 | exit 1 85 | fi 86 | 87 | echo "[+] Logged in successfully. UID: $USER_ID" 88 | 89 | 90 | # Step 4: Live fetch of 5G NR SA stats every 0.5s 91 | while true; do 92 | clear 93 | echo "[*] Fetching 5G NR SA stats at $(date '+%H:%M:%S')..." 94 | 95 | STATS=$(curl -sk -X GET "$STATS_URL" \ 96 | -H "Cookie: Secure; LANGUAGE=1; expert=true; UID=${USER_ID}; FIRST_LOGIN_FLAG=0; privilege=0; login_block=false" \ 97 | -H "Accept: application/json") 98 | 99 | echo "[+] 5G NR SA Statistics:" 100 | echo "$STATS" | jq 101 | 102 | sleep 0.5 103 | done 104 | 105 | -------------------------------------------------------------------------------- /instructions/JAF-ODU-Access-Via-Bluetooth.md: -------------------------------------------------------------------------------- 1 | # How to Access ODU WEB UI on Android 2 | 3 | This guide explains how to find the IP address of the ODU (Outdoor Unit) and access its WEB UI. It provides two methods: 4 | 5 | 1. **Primary Method**: Using **Termux** and `nmap` for fast command-line scanning. 6 | 2. **Alternative Method**: Using the **PingTools Network Utilities** app if Termux fails. 7 | 8 | --- 9 | 10 | ## 📋 Prerequisites 11 | 12 | Ensure you have the following apps installed on your Android device: 13 | 14 | - **J**\*\* **Field Diagnostic App** 15 | - **J**\*\* **Home App** 16 | - **Termux** 17 | - (Optional) **PingTools Network Utilities**: [Download from Play Store](https://play.google.com/store/apps/details?id=ua.com.streamsoft.pingtools&hl=en_IN) 18 | 19 | --- 20 | 21 | ## 🔧 Setup Instructions 22 | 23 | ### 1. Set Up J** Apps 24 | 25 | 1. **Install J**\*\* **Apps** 26 | - Install **J**\*\* **Field Diagnostic App** and **J**\*\* **Home App** from the Google Play Store. 27 | 28 | 2. **Login** 29 | - Open **J**\*\* **Home App**. 30 | - Log in using your J** account credentials. 31 | 32 | 3. **Scan QR Code** 33 | - Open the **J**\*\* **Field Diagnostic App**. 34 | - Scan the QR code on the ODU. 35 | 36 | 4. **Pair & Enable Bluetooth Tethering** 37 | - When prompted, open **J**\*\* **Home App**. 38 | - Follow instructions to **pair** and **enable Bluetooth tethering**. 39 | - Keep both apps running in the background. 40 | 41 | --- 42 | 43 | ## 🔍 Method 1: Using Termux (Preferred) 44 | 45 | ### Step A: Launch Termux 46 | 47 | Open **Termux** and run: 48 | ```bash 49 | ifconfig 50 | ``` 51 | 52 | Look for a `bt-pan` interface, e.g.: 53 | ``` 54 | bt-pan: flags=4163 mtu 1500 55 | inet 192.168.44.1 netmask 255.255.255.0 broadcast 192.168.44.255 56 | ``` 57 | 58 | > If `bt-pan` is not visible, make sure both J** apps are open and tethering is active. 59 | 60 | ### Step B: Run Nmap to Discover ODU IP 61 | 62 | Run: 63 | ```bash 64 | nmap -p 443 192.168.44.0/24 65 | ``` 66 | 67 | Example output: 68 | ``` 69 | Nmap scan report for 192.168.44.1 (gateway) 70 | 443/tcp closed https 71 | 72 | Nmap scan report for 192.168.44.150 (ODU) 73 | 443/tcp open https 74 | ``` 75 | 76 | > The IP with **port 443 open** (like `192.168.44.150`) is your ODU's address. 77 | 78 | --- 79 | 80 | ## 📱 Method 2: Using PingTools (If Termux Fails) 81 | 82 | 1. **Install the App** 83 | - Get **PingTools**: [Google Play Store](https://play.google.com/store/apps/details?id=ua.com.streamsoft.pingtools&hl=en_IN) 84 | 85 | 2. **Open Subnet Scanner** 86 | - Tap **menu icon (☰)** > **"Subnet Scanner"** 87 | 88 | 3. **Configure IP Range** 89 | - Tap **settings icon (⚙️)** > **Manual Configuration** 90 | - Set: 91 | - **Start IP**: `192.168.44.0` 92 | - **End IP**: `192.168.44.255` 93 | - Tap **Save** 94 | 95 | 4. **Start Scan** 96 | - Tap **Scan** to begin. 97 | - Look for a device with **port 443 open** or labeled **ODU** 98 | 99 | --- 100 | 101 | ## 🌐 Accessing the ODU WEB UI 102 | 103 | 1. Open a browser on your phone. 104 | 2. Go to: 105 | ``` 106 | https:// 107 | ``` 108 | Example: 109 | ``` 110 | https://192.168.44.150 111 | ``` 112 | 113 | 3. Tap **"Advanced > Proceed"** if a security warning appears. 114 | 115 | --- 116 | 117 | ## 🛠️ Troubleshooting 118 | 119 | - Ensure Bluetooth tethering is **enabled**. 120 | - Keep **J**\*\* **apps** running in the background. 121 | - If Termux shows no `bt-pan`, restart Bluetooth and reconnect. 122 | - Retry scanning via Termux or use PingTools as a fallback. 123 | 124 | --- 125 | 126 | > ✅ Use Termux for speed and precision. Use PingTools for a user-friendly visual method. 127 | -------------------------------------------------------------------------------- /scripts/opensync_disabler.sh: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | 3 | echo "==============================================" 4 | echo " opensync_disabler " 5 | echo " Disable Opensync-related services " 6 | echo " and patch init scripts " 7 | echo " " 8 | echo " Usage: " 9 | echo " ./opensync_disabler.sh " 10 | echo " ./opensync_disabler.sh --restore " 11 | echo "==============================================" 12 | 13 | 14 | set -e 15 | 16 | SERVICES="healthcheck opensync jioWifiManagerStartup jioDscpPriority jioWifiNotifierStartup jioWifiLoggerStartup" 17 | INIT_SCRIPTS="plumeConfigMerge platformConfigMerge opensync dnsmasq" 18 | 19 | restore_script() { 20 | SCRIPT="/etc/init.d/$1" 21 | BACKUP="$SCRIPT.bak" 22 | 23 | if [ -f "$BACKUP" ]; then 24 | echo " -> Restoring $SCRIPT" 25 | cp "$BACKUP" "$SCRIPT" || { 26 | echo " !! Failed to restore $SCRIPT from backup" 27 | return 1 28 | } 29 | chmod +x "$SCRIPT" 30 | else 31 | echo " !! No backup found for $SCRIPT" 32 | fi 33 | } 34 | 35 | patch_script() { 36 | SCRIPT="/etc/init.d/$1" 37 | [ -f "$SCRIPT" ] || return 38 | 39 | # Always backup before patching 40 | cp "$SCRIPT" "$SCRIPT.bak" 41 | 42 | case "$1" in 43 | plumeConfigMerge|platformConfigMerge) 44 | # Collapse any PlumeEnabled assignment down to 0 45 | sed -i 's/PlumeEnabled=".*"/PlumeEnabled="0"/g' "$SCRIPT" 46 | ;; 47 | opensync) 48 | # Replace service-enabled function to always return false 49 | awk ' 50 | BEGIN {skip=0} 51 | /^opensync_service_enabled\(\)/ { 52 | print "opensync_service_enabled() {\n false\n}" 53 | skip=1 54 | next 55 | } 56 | skip && /^\}/ { skip=0; next } 57 | !skip { print } 58 | ' "$SCRIPT.bak" > "$SCRIPT" 59 | ;; 60 | dnsmasq) 61 | # Comment out the bind-dynamic append_bool line 62 | sed -i '/append_bool.*nonwildcard.*--bind-dynamic/ s/^/#/' "$SCRIPT" 63 | ;; 64 | esac 65 | } 66 | 67 | disable_services() { 68 | echo "[*] Disabling services..." 69 | for svc in $SERVICES; do 70 | INIT_PATH="/etc/init.d/$svc" 71 | if [ -x "$INIT_PATH" ]; then 72 | echo " -> Disabling $svc" 73 | $INIT_PATH stop 2>/dev/null || true 74 | $INIT_PATH disable 2>/dev/null || true 75 | chmod -x "$INIT_PATH" 76 | else 77 | echo " !! Service $svc not found or not executable" 78 | fi 79 | done 80 | } 81 | 82 | restore_services() { 83 | echo "[*] Restoring services..." 84 | for svc in $SERVICES; do 85 | # If we have a backed-up init script, restore and re-enable it 86 | if [ -f "/etc/init.d/$svc.bak" ]; then 87 | echo " -> Re-enabling $svc" 88 | cp "/etc/init.d/$svc.bak" "/etc/init.d/$svc" 89 | chmod +x "/etc/init.d/$svc" 90 | /etc/init.d/$svc enable 2>/dev/null || true 91 | fi 92 | done 93 | } 94 | 95 | # Main execution flow 96 | if [ "$1" = "--restore" ] || [ "$1" = "-r" ]; then 97 | echo "[*] Restoring all changes..." 98 | for script in $INIT_SCRIPTS; do 99 | restore_script "$script" 100 | done 101 | restore_services 102 | echo "[*] Restore complete." 103 | else 104 | disable_services 105 | echo "[*] Patching init scripts..." 106 | for script in $INIT_SCRIPTS; do 107 | patch_script "$script" 108 | done 109 | echo "[*] Done. All services disabled and init scripts patched." 110 | echo "[*] Please reboot the device for changes to take effect." 111 | fi 112 | -------------------------------------------------------------------------------- /instructions/JAF-IDU-UBOOT-Access.md: -------------------------------------------------------------------------------- 1 | # JAF IDU U-Boot Access 2 | 3 | _Disclaimer: This is ONLY for educational purposes, No one is responsible for any type of damage. So be aware._ 4 | 5 | _J** has cleverly locked u-boot access behind a custom username and password that are unique for each model. But fear not, brave soul! Follow these sacred steps, and thou shalt be granted access to the realm of u-boot by the almighty gods themselves._ 6 | 7 | ## Step 1: Prepping the IDU :P 8 | 9 | Hop onto [SSH on the IDU](./JAF-IDU-Root-Access.md) and run the commands below 10 | 11 | - Username: `/etc/mfg/gm_mtc/gm_factory_init.sh get sn` 12 | - Password: `/etc/mfg/gm_mtc/gm_factory_init.sh get uboot_passwd` 13 | 14 | Simple, yes ??? 15 | 16 | ## Step 2: Cooking time :- 17 | 18 | 1. Connect your (usb-to-tll/arduino/esp32/whatever jank you got) to the [UART ports](./JAF-IDU-UART-Access.md) and keep the enter key pressed to pause boot. 19 | 20 | 2. Enter Username and Password and VOILA! You should be greeted into the uboot console 21 | 22 | ## U-Boot Commands 23 | 24 | ```bash 25 | MT7986> ? 26 | 27 | ?         - alias for 'help' 28 | 29 | base      - print or set address offset 30 | 31 | bdinfo    - print Board Info structure 32 | 33 | bl2       - BL2 utility commands 34 | 35 | blkcache  - block cache diagnostics and control 36 | 37 | boot      - boot default, i.e., run 'bootcmd' 38 | 39 | bootd     - boot default, i.e., run 'bootcmd' 40 | 41 | bootflow  - Boot flows 42 | 43 | booti     - boot Linux kernel 'Image' format from memory 44 | 45 | bootm     - boot application image from memory 46 | 47 | bootmenu  - ANSI terminal bootmenu 48 | 49 | bootp     - boot image via network using BOOTP/TFTP protocol 50 | 51 | cmp       - memory compare 52 | 53 | coninfo   - print console devices and information 54 | 55 | cp        - memory copy 56 | 57 | crc32     - checksum calculation 58 | 59 | echo      - echo args to console 60 | 61 | editenv   - edit environment variable 62 | 63 | env       - environment handling commands 64 | 65 | fdt       - flattened device tree utility commands 66 | 67 | fip       - FIP utility commands 68 | 69 | go        - start application at address 'addr' 70 | 71 | gpio      - query and control gpio pins 72 | 73 | help      - print command description/usage 74 | 75 | httpd     - Start failsafe HTTP server 76 | 77 | iminfo    - print header information for application image 78 | 79 | imxtract  - extract a part of a multi-image 80 | 81 | itest     - return true/false on integer compare 82 | 83 | loadb     - load binary file over serial line (kermit mode) 84 | 85 | loads     - load S-Record file over serial line 86 | 87 | loadx     - load binary file over serial line (xmodem mode) 88 | 89 | loady     - load binary file over serial line (ymodem mode) 90 | 91 | loop      - infinite loop on address range 92 | 93 | lzmadec   - lzma uncompress a memory region 94 | 95 | md        - memory display 96 | 97 | mm        - memory modify (auto-incrementing address) 98 | 99 | mmc       - MMC sub system 100 | 101 | mmcinfo   - display MMC info 102 | 103 | mtd       - MTD utils 104 | 105 | mtkautoboot- Display MediaTek bootmenu 106 | 107 | mtkboardboot- Boot MTK firmware 108 | 109 | mtkload   - MTK image loading utility 110 | 111 | mtkupgrade- MTK firmware/bootloader upgrading utility 112 | 113 | mw        - memory write (fill) 114 | 115 | nand      - NAND utility 116 | 117 | net       - NET sub-system 118 | 119 | nfs       - boot image via network using NFS protocol 120 | 121 | nm        - memory modify (constant address) 122 | 123 | nmbm      - NMBM utility commands 124 | 125 | panic     - Panic with optional message 126 | 127 | pci       - list and access PCI Configuration Space 128 | 129 | ping      - send ICMP ECHO_REQUEST to network host 130 | 131 | pinmux    - show pin-controller muxing 132 | 133 | printenv  - print environment variables 134 | 135 | pstore    - Manage Linux Persistent Storage 136 | 137 | pwm       - control pwm channels 138 | 139 | random    - fill memory with random pattern 140 | 141 | reset     - Perform RESET of the CPU 142 | 143 | run       - run commands in an environment variable 144 | 145 | saveenv   - save environment variables to persistent storage 146 | 147 | setenv    - set environment variables 148 | 149 | setexpr   - set environment variable as the result of eval expression 150 | 151 | sleep     - delay execution for some time 152 | 153 | smc       - Issue a Secure Monitor Call 154 | 155 | source    - run script from memory 156 | 157 | tftpboot  - load file via network using TFTP protocol 158 | 159 | ubi       - ubi commands 160 | 161 | ubifsload - load file from an UBIFS filesystem 162 | 163 | ubifsls   - list files in a directory 164 | 165 | ubifsmount- mount UBIFS volume 166 | 167 | ubifsumount- unmount UBIFS volume 168 | 169 | version   - print monitor, compiler and linker version 170 | ``` 171 | -------------------------------------------------------------------------------- /Scripts-and-Hacks.md: -------------------------------------------------------------------------------- 1 | | sr.No | Name | author | 2 | | ----- | -------------------------------------------------------------- | ----------------- | 3 | | 01 | [Root enabler for Extender/IDU](#root-enabler-for-extenderidu) | @Viraniac | 4 | | 02 | [Network stats logger for ODU](#network-stats-logger-for-odu) | @BlueNecko | 5 | | 03 | [Opensync disabler](#opensync-disabler) | @Xumi59,BlueNecko | 6 | | 04 | [ODU Local link generator](#odu-local-link-generator) | @timeisexpensivee | 7 | 8 | ## Root enabler for Extender/IDU 9 | ### script: [enableRootSSH](scripts/enableRootSSH.sh) 10 | This is an alternate method for rooting, alt to the OG manual method of editing the files. This has been tested with few models such as Extenders and idu6801. Although it should work the same for every other idu too, but it isn't confirmed yet. 11 | 12 | ## Network stats logger for ODU 13 | This script works by utilizing the restful api endpoints provided by the odu. These are the stats which you can see in the webui of the odu, but in a very raw form which can be utilized for studying the network fluctuations and uptime. If your odu doesn't use restfull api's the data can still be captured but you will have to write the script for that. 14 | 15 | The script is supposed to run on any device (primarily idu) which is connected to the odu via an ether link. The script does automatic auth given it knows the salt and the hashed password. 16 | ##### Note: password automation is still under development and for now needs manual hash capture 17 | 18 | ### script: [odu_stats.sh](scripts/odu_stats.sh) 19 | You needs to edit the site, api, login and filepath variables before executing. The script will save the data in a .csv file in the following format. 20 | ![](assets/ODU_STATS_SCRIPT.png) 21 | ### script: [odu_stats_live.sh](scripts/odu_stats_live.sh) 22 | This script is supposed to be ran live to help with odu mounting and alignment(it's barebone for now) 23 | ![](assets/ODU_STATS_LIVE_SCRIPT.png) 24 | 25 | ### Formatting and graph plots 26 | These are simple python scripts which will plot graphs for you, for now only few are there, more may or may not be added in future. 27 | 28 | ### script: [relation.py](scripts/realation.py) 29 | ![RELATION](assets/RELATION.png) 30 | 31 | 32 | 33 | ## Opensync disabler 34 | services to be disabled on startup - healthcheck, opensync, jioWifiManagerStartup, jioDscpPriority, jioWifiNotifierStartup, jioWifiLoggerStartup 35 | 36 | script changes - /etc/init.d/plumeConfigMerge , /etc/init.d/platformConfigMerge, /etc/init.d/opensync 37 | 38 | ### Changes made to startup scripts 39 | Note: Changes have been marked with `###` comments, only the part of the file that has been changed is shown, rest of the file isnt shown. 40 | 1. plumeConfigMerge 41 | ```sh 42 | #!/bin/sh /etc/rc.common 43 | 44 | # Copyright© 2023 Jio Platforms Ltd. 45 | 46 | START=14 47 | 48 | PlumeEnabled="0" ### changes to 0 for plume disabled 49 | 50 | if [ -f "/usr/opensync/bin/dm" ]; then 51 | PlumeEnabled="0" ### changes to 0 for plume disabled 52 | fi 53 | 54 | if [ "$PlumeEnabled" = "0" ]; then ### changes to 0 for plume disabled 55 | network_brlanuci q get network.brlan 56 | 57 | if [ -n "$network_brlan" ]; then 58 | ######### For network config file changes ########### uci delete network.brlan 59 | rule_name=$(uci -q add network switch) 60 | uci batch << EOF 61 | set network.$rule_name.name=switch 62 | set network.$rule_name.name=switch0 63 | set network.$rule_name.reset=1 64 | ``` 65 | 66 | 2. platformConfigMerge 67 | ```sh 68 | #!/bin/sh /etc/rc.common 69 | 70 | # Copyright© 2023 Jio Platforms Ltd. 71 | 72 | START=15 73 | 74 | PlumeEnabled="0" 75 | 76 | if [ -f "/usr/opensync/bin/dm" ]; then 77 | PlumeEnabled="0" ### changes to 0 for plume disabled 78 | fi 79 | 80 | ######## Plume disabled, update network and dhcp config file #*** 81 | if [ "$PlumeEnabled" = "0" ]; then 82 | config_network='uci -q get network.brlan.name 83 | 84 | if [ -z "$config_network" ]; then 85 | uci delete network.@switch_vlan[2] 86 | uci delete network.@switch_vlan[1] 87 | uci delete network.@switch_vlan[0] 88 | uci delete network.@switch[0] 89 | uci set network.brlan="device" 90 | uci set network.brlan.name='br-lan' 91 | fi 92 | fi 93 | 94 | ``` 95 | 96 | 3. opensync 97 | ```sh 98 | #!/bin/sh -e 99 | INSTALL_PREFIX=/usr/opensync 100 | 101 | START=99 102 | 103 | PID_FILE=/var/run/dm.pid 104 | BIN_DIR=${INSTALL_PREFIX}/bin 105 | 106 | opensync_service_enabled() 107 | { 108 | false ### changed to false to disable opensync 109 | } 110 | 111 | opensync_post_start() 112 | { 113 | ${INSTALL_PREFIX}/bin/ipmond & 114 | } 115 | ``` 116 | 117 | Note: script is underwork, anything can go wrong, so do not be dumb. 118 | ### script: [opensync_disabler](scripts/opensync_disabler.sh) 119 | 120 | 121 | ## ODU Local link generator 122 | This script works on principle of ipv6 local-link address generation using the mac address of ODU 123 | Converts a MAC address (e.g., 00:06:AE:A3:AE:90) to IPv6 link-local (EUI-64) 124 | Ensure MAC is lowercase and colon-separated 125 | 126 | ![](assets/FIND_ODU_LOCAL_LINK.png) 127 | ### script: [find_oduv6](scripts/find_oduv6.sh) -------------------------------------------------------------------------------- /scripts/breeze.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ONLY for educational purposes, No one is responsible for any type of damage. 4 | 5 | # Usage: ./breeze.sh 6 | 7 | # Exit immediately if a command exits with a non-zero status 8 | set -e 9 | 10 | # Function to display usage instructions 11 | usage() { 12 | echo "Usage: $0 " 13 | echo "Example: $0 backup.enc" 14 | exit 1 15 | } 16 | 17 | # Function to check the success of the last executed command 18 | check_success() { 19 | if [ "$?" -ne 0 ]; then 20 | echo "Error: $1 failed." 21 | exit 1 22 | fi 23 | } 24 | 25 | # Check if the correct number of arguments is provided 26 | if [ "$#" -ne 1 ]; then 27 | echo "Error: Incorrect number of arguments." 28 | usage 29 | fi 30 | 31 | # Assign command-line arguments to variables 32 | ENCRYPTED_FILE="$1" 33 | DECRYPTED_FILE="dec_backup_og.tar.gz" 34 | 35 | # Check if the encrypted file exists 36 | if [ ! -f "$ENCRYPTED_FILE" ]; then 37 | echo "Error: Encrypted file '$ENCRYPTED_FILE' does not exist." 38 | exit 1 39 | fi 40 | 41 | # Check for required tools 42 | REQUIRED_TOOLS=("openssl" "tar" "gunzip") 43 | for tool in "${REQUIRED_TOOLS[@]}"; do 44 | if ! command -v "$tool" &> /dev/null; then 45 | echo "Error: '$tool' is not installed. Please install it before running this script." 46 | exit 1 47 | fi 48 | done 49 | 50 | # Step 1: Decrypt the configuration backup 51 | echo "Step 1: Decrypting the configuration backup..." 52 | openssl enc -pbkdf2 -in "$ENCRYPTED_FILE" -out "$DECRYPTED_FILE" -d -aes256 -k "/etc/server.key" || { 53 | echo "Warning: Failed to decrypt the backup. The key may be invalid." 54 | exit 1 55 | } 56 | check_success "Decryption" 57 | 58 | # Step 2: Extract the decrypted backup 59 | echo "Step 2: Extracting the decrypted backup..." 60 | EXTRACT_DIR="extracted_backup" 61 | mkdir -p "$EXTRACT_DIR" 62 | tar -xzvf "$DECRYPTED_FILE" -C "$EXTRACT_DIR" 63 | check_success "Extraction" 64 | 65 | # Step 3: Modify the necessary files in the backup 66 | SHADOW_FILE="$EXTRACT_DIR/etc/shadow" 67 | MWAN_FILE="$EXTRACT_DIR/etc/mwan3.user" 68 | 69 | # Ensure the shadow file exists 70 | if [ ! -f "$SHADOW_FILE" ]; then 71 | echo "Error: Shadow file '$SHADOW_FILE' does not exist in the backup." 72 | exit 1 73 | fi 74 | 75 | # Generate a new root password hash 76 | read -sp "Enter desired root password: " ROOT_PASSWORD 77 | echo 78 | read -sp "Enter salt for password hashing: " SALT 79 | echo 80 | 81 | if [ -z "$ROOT_PASSWORD" ] || [ -z "$SALT" ]; then 82 | echo "Error: Password and salt cannot be empty." 83 | exit 1 84 | fi 85 | 86 | NEW_PASSWORD_HASH=$(openssl passwd -1 -salt "$SALT" "$ROOT_PASSWORD") 87 | 88 | # Backup the original shadow file 89 | cp "$SHADOW_FILE" "${SHADOW_FILE}.bak" 90 | 91 | # Update the root password hash in the shadow file 92 | echo "Step 3: Setting new root password hash..." 93 | 94 | # check if macos 95 | if [[ "$OSTYPE" == "darwin"* ]]; then 96 | sed -i '' "s|^root:[^:]*:|root:${NEW_PASSWORD_HASH}:|" "$SHADOW_FILE" 97 | else 98 | sed -i "s|^root:[^:]*:|root:${NEW_PASSWORD_HASH}:|" "$SHADOW_FILE" 99 | fi 100 | check_success "Updating root password hash" 101 | 102 | # Ensure the mwan3.user file exists, or prompt for alternative methods 103 | if [ ! -f "$MWAN_FILE" ]; then 104 | echo "Warning: mwan3.user file '$MWAN_FILE' does not exist in the backup." 105 | read -p "Would you like to use an alternative method (e.g., /etc/firewall.user)? (y/n): " ALTERNATE_METHOD 106 | if [[ "$ALTERNATE_METHOD" =~ ^[Yy]$ ]]; then 107 | FIREWALL_FILE="$EXTRACT_DIR/etc/firewall.user" 108 | mkdir -p "$(dirname "$FIREWALL_FILE")" 109 | echo 'dropbear -p 0.0.0.0:22' > "$FIREWALL_FILE" 110 | echo "Step 4 (Alternative): Configuring /etc/firewall.user to start dropbear..." 111 | check_success "Creating firewall.user for dropbear" 112 | echo "Note: After gaining SSH access, it is recommended to move the configuration to /etc/rc.local:" 113 | echo " Add 'dropbear -p 0.0.0.0:22' before the 'exit 0' line in /etc/rc.local." 114 | echo " Delete /etc/firewall.user after SSH setup to avoid unnecessary configurations." 115 | else 116 | echo "Error: mwan3.user is not found, and no alternative method selected. Exiting..." 117 | exit 1 118 | fi 119 | else 120 | # Append dropbear command to mwan3.user 121 | echo "Step 4: Configuring mwan3.user to start dropbear on Dual WAN activation..." 122 | echo 'dropbear -p 0.0.0.0:22' >> "$MWAN_FILE" 123 | check_success "Configuring dropbear in mwan3.user" 124 | fi 125 | 126 | # Step 5: Repackage the modified backup 127 | echo "Step 5: Repackaging the modified backup..." 128 | MODIFIED_TAR="backup_mod.tar.gz" 129 | tar -czvf "$MODIFIED_TAR" -C "$EXTRACT_DIR" . 130 | check_success "Repackaging" 131 | 132 | # Step 6: Re-encrypt the modified backup 133 | echo "Step 6: Re-encrypting the modified backup..." 134 | openssl enc -pbkdf2 -in "$MODIFIED_TAR" -out "encrypted_backup_mod.tar.gz" -e -aes256 -k "/etc/server.key" 135 | check_success "Re-encryption" 136 | 137 | # Step 7: Cleanup temporary files 138 | echo "Step 7: Cleaning up temporary files..." 139 | rm -rf "$DECRYPTED_FILE" "$EXTRACT_DIR" "$MODIFIED_TAR" 140 | check_success "Cleanup" 141 | 142 | # Final Instructions 143 | echo "========================================" 144 | echo "The modified and re-encrypted backup is ready as 'encrypted_backup_mod.tar.gz'." 145 | echo "Follow these steps to restore and gain root access:" 146 | echo "1. Upload 'encrypted_backup_mod.tar.gz' using the device's backup restore feature." 147 | echo "2. Navigate to https://192.168.31.1/#/WAN/DualWan and enable Dual WAN." 148 | echo " This will reboot the device and enable SSH access." 149 | echo " If /etc/firewall.user was created, it will also start Dropbear on port 22." 150 | echo "3. After gaining SSH access, to make it persistent:" 151 | echo " a. Add 'dropbear -p 0.0.0.0:22' to '/etc/rc.local' before the 'exit 0' line." 152 | echo " b. Delete '/etc/firewall.user' if it was used for SSH access." 153 | echo "4. Disable Dual WAN as it may not function correctly and could cause issues." 154 | echo "========================================" 155 | echo "All steps completed successfully!" 156 | -------------------------------------------------------------------------------- /instructions/JAF-IDU-Root-Access.md: -------------------------------------------------------------------------------- 1 | # A walk-through onto getting root access in the JAF Series of Routers 2 | 3 | _Disclaimer: This is ONLY for educational purposes, No one is responsible for any type of damage. So be aware._ 4 | 5 | **You can use [this script](../scripts/breeze.sh) to automatically get root access. Remember to have openssl, tar, and gunzip installed. The script only works in UNIX-like systems (Linux, macOS, BSD, etc.)** 6 | 7 | ## Intro 8 | 9 | AF's firmware has drastically changed since JF, with a new firmware based on OpenWRT, it gets quite easier to handle than their proprietary buildroot based build on the JFs. 10 | 11 | There are 5 "IDUs" (Indoor Units): 12 | IDU6101 - Arcaydan 13 | IDU6801 - GMOB 14 | IDU6601 - SPED 15 | IDU6401 - Sercomm 16 | IDU6701 - Skyworth 17 | IDU6811 - Telpa (IPQ9554) 18 | 19 | Out of these, some are Mediatek-based, specifically the MTK7986 SoC. I have confirmed that IDU6801 and IDU6401 have the MTK Chipsets. The rest have not been confirmed. 20 | Looking around at their new WebUI, they have switched to calling it JWRT, with most of the data coming from an API Endpoint WCGI. From the JWRT tags, we assumed that the firmware would be based on OpenWRT, especially when the MTK7986 does seem to have support by BananaPi's R3 Router. 21 | 22 | ## Gathering the Files 23 | 24 | With the firmware in hand, and some `binwalk`ing around, we now have the rootfs. It was clear by now, both from the file structure and a lot of references, that the firmware was indeed based on OpenWRT, specifically some OpenWRT 21.02 Snapshot from March 2021 (as the packages suggest). The firmware has been frozen, meaning that it is incredibly insecure and forever stuck with the flaws in the packages installed. This is not that big of an issue if it was their own home-made firmware, but the fact that they are using `luci` and `uci` APIs for almost anything is really concerning. 25 | 26 | ## Breaking the encryption 27 | 28 | History repeats itself, and it did yet again with the `server.key` being reutilized yet again as the encryption key for their Config Backups (well, actually they didn't; rather they used the string `"/etc/server.key"` to encrypt the config backup), not the case for their Debug Logs (dbglog) though. This time, they switched to AES-256 instead of AES-128 like the last time. A certain binary, `jcrypt`, acts as the sole encryption/decryption service. A lot of references throughout the system, with it even being used to restore the configuration. Doing a quick `strings` on jcrypt, it can be found that they are indeed using almost the same openssl encryption command, and to find the exact key, we just had to `strace` it a bit, which is quite easy with QEMU's AARCH64 Static Chroot. 29 | 30 | Thus, the command stands: 31 | 32 | ```shell 33 | openssl enc -pbkdf2 -in encryptedfile -out decryptedfile -d -aes256 -k "/etc/server.key" 34 | ``` 35 | 36 | _P.S.: Yeah this is funny how J used the string `"/etc/server.key"` to encrypt the backup rather than using the file itself. Even kids know that they should have used `-kfile` instead of `-k`_ 37 | 38 | As we unarchive the backup, we find that it is a snapshot of `/etc`, this makes things a lot more easier for us to achieve, because it contains both `passwd` and `shadow` files. It also contains `mwan3.user`, which is a shell script that activates when the Dual WAN Mode of the AF is activated. You can activate the Dual WAN from here: 39 | 40 | ## Figuring out the rest 41 | 42 | Almost there. With `dropbear` already being installed in the firmware, it was just a matter of changing the password of root and getting dropbear to run. I decided to take the harder route and just change the root password hash in `/etc/shadow` (You can generate yours using this command: `openssl passwd -1 -salt ENTER_YOUR_SALT "ENTER_YOUR_PASSWORD"`) as the root FS is persistent, and rewriteable. But, you can also change the password as you start dropbear. It's simple from here. 43 | 44 | Open `mwan3.user` in any text editor (code editors preferred), go to the last line, and add: 45 | 46 | ```shell 47 | dropbear -p 0.0.0.0:22 48 | ``` 49 | 50 | and if you want to change the password, in the next line: 51 | 52 | ```shell 53 | echo -e \"password\npassword\" | passwd root 54 | ``` 55 | 56 | Now to wrap up the backup and finally get root access, all you have to do is generate a `.tar.gz` of the file, and then re-encrypt it with the server.key with this command: 57 | 58 | ```shell 59 | openssl enc -pbkdf2 -in decryptedfile -out encryptedfile -e -aes256 -k "/etc/server.key" 60 | ``` 61 | 62 | _P.S.: Yeah! Please don't re-encrypt the file with the actual `server.key`. Rather use the string `/etc/server.key`_ 63 | 64 | ## Stairway to Heaven 65 | 66 | Drop the encrypted tar.gz (remember to have .tar.gz as the extension of the file) into the backup restore, let the device reboot. 67 | Now, go to and enable it, the device will reboot again, and now ssh should be up and running! 68 | 69 | To persist everything and to be able to disable Dual WAN, you just need to add the dropbear command to the end of `/etc/rc.local`, and et voila! 70 | You might need to do this every update, but at least not at restart from now on! 71 | 72 | ## Suggestions 73 | 74 | Block `fota.slv.kai.jphone.net` at /etc/hosts: 75 | 76 | ```shell 77 | 0.0.0.0 fota.slv.kai.jphone.net 78 | ``` 79 | 80 | Disable TR-069 at /etc/config/tr069: 81 | Replace `config acs` with: 82 | 83 | ```conf 84 | config acs 85 | option periodic_enable '0' 86 | option enablecwmp '0' 87 | option interface 'eth0' 88 | option isConnected '1' 89 | ``` 90 | 91 | ### Disable Wifi 92 | 93 | ```shell 94 | ovsdb-client transact '[ "Open_vSwitch", { "op": "update", "table": "Wifi_Radio_Config", "where": [], "row": { "enabled": false } } ]' 95 | ``` 96 | 97 | ### Enable Wifi 98 | 99 | ```shell 100 | ovsdb-client transact '[ "Open_vSwitch", { "op": "update", "table": "Wifi_Radio_Config", "where": [], "row": { "enabled": true } } ]' 101 | ``` 102 | 103 | ### Disable wifi auto restart 104 | 105 | ```shell 106 | vim /usr/opensync/scripts/healthcheck.funcs.sh 107 | ``` 108 | 109 | Edit the file and set the value of Healthcheck_Enabled() to false instead of true. 110 | -------------------------------------------------------------------------------- /scripts/enableRootSSH.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ONLY for educational purposes, No one is responsible for any type of damage. 4 | 5 | # Usage: ./enableRootSSH.sh 6 | 7 | # Exit immediately if a command exits with a non-zero status 8 | set -e 9 | 10 | # Function to display usage instructions 11 | usage() { 12 | echo "This script was specifically made for Jio Extender, though this might work for normal IDUs; it is still advised to use the normal breeze.sh" 13 | echo "Usage: $0 " 14 | echo "Example: $0 192.168.31.1" 15 | exit 1 16 | } 17 | 18 | # Function to check the success of the last executed command 19 | check_success() { 20 | if [ "$?" -ne 0 ]; then 21 | echo "Error: $1 failed." 22 | exit 1 23 | fi 24 | } 25 | 26 | check_json_success() { 27 | if ! jq '.status' curl.output 2>/dev/null | grep -q OK ; then 28 | echo "Error: $1 failed." 29 | exit 1 30 | fi 31 | } 32 | 33 | # Check if the correct number of arguments is provided 34 | if [ "$#" -ne 1 ]; then 35 | echo "Error: Incorrect number of arguments." 36 | usage 37 | fi 38 | 39 | # Assign command-line arguments to variables 40 | DEVICE_IP="$1" 41 | ENCRYPTED_FILE="conf.enc" 42 | DECRYPTED_FILE="conf.dec" 43 | MODIFIED_TAR="conf_new.tar.gz" 44 | MODIFIED_TAR_ENC="conf_new.enc" 45 | 46 | # Check for required tools 47 | REQUIRED_TOOLS=("cut" "curl" "dd" "gunzip" "jq" "openssl" "sed" "tar") 48 | for tool in "${REQUIRED_TOOLS[@]}"; do 49 | if ! command -v "$tool" &> /dev/null; then 50 | echo "Error: '$tool' is not installed. Please install it before running this script." 51 | exit 1 52 | fi 53 | done 54 | 55 | if ! grep --version | grep -v BSD | grep -q GNU; then 56 | echo "Error: GNU grep is not installed. Please install it before running the script." 57 | exit 1 58 | fi 59 | 60 | read -sp "Please enter your JAF IDU device admin password:" DEVICE_PASSWORD 61 | 62 | # Step 1: Login to the device 63 | echo "Step 1: Trying to login to the router..." 64 | 65 | curl "https://${DEVICE_IP}/WCGI" \ 66 | -H 'Content-Type: application/json' \ 67 | --data-raw "{\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"username\":\"admin\",\"password\":\"${DEVICE_PASSWORD}\"}}" \ 68 | --insecure >curl.output 69 | 70 | check_json_success "Device login" 71 | 72 | AUTH_TOKEN=$(jq -r '.results.token' curl.output 2>/dev/null | cut -f 1 -d\ ) 73 | COOKIE=$(jq -r '.results.token' curl.output 2>/dev/null | cut -f 2 -d\ ) 74 | 75 | curl "https://${DEVICE_IP}/WCGI" \ 76 | -H "Cookie: cSupport=1; sysauth=${COOKIE}" \ 77 | -H 'Content-Type: application/json' \ 78 | --data-raw "{\"jsonrpc\":\"2.0\",\"method\":\"postLogin\",\"params\":{\"authHeader\":\"Bearer ${AUTH_TOKEN}\"}}" \ 79 | --insecure >curl.output 80 | 81 | check_json_success "Device post login" 82 | 83 | # Step 2: Downloading backup file 84 | echo "Step 1: Downloading backup file..." 85 | 86 | curl "https://${DEVICE_IP}/WCGI" \ 87 | -H "Authorization: Bearer ${AUTH_TOKEN}" \ 88 | -H "Cookie: cSupport=1; sysauth=${COOKIE}" \ 89 | -H 'Content-Type: application/json' \ 90 | --data-raw '{"jsonrpc":"2.0","method":"getBackupConfiguration","fileDownload":"yes"}' \ 91 | --insecure --output ${ENCRYPTED_FILE} 92 | 93 | check_success "Downloading backup file" 94 | 95 | # Step 3: Decrypting the configuration backup 96 | echo "Step 3: Decrypting the configuration backup..." 97 | openssl enc -pbkdf2 -in "$ENCRYPTED_FILE" -out "$DECRYPTED_FILE" -d -aes256 -k "/etc/server.key" 98 | check_success "Backup file decryption" 99 | 100 | # Step 4: Extract the decrypted backup 101 | echo "Step 4: Extracting the decrypted backup..." 102 | EXTRACT_DIR="extracted_backup" 103 | mkdir -p "$EXTRACT_DIR" 104 | 105 | gzip_index=$(LANG=ISO-8859-1 grep -obUaP "\x1f\x8b\x08" ${DECRYPTED_FILE} 2>/dev/null | head -n 1 | LANG=ISO-8859-1 cut -f 1 -d:) 106 | 107 | [ -n ${gzip_index} ] || { 108 | echo "Downloaded backup file is invalid" 109 | exit 1 110 | } 111 | 112 | if [ ${gzip_index} != 0 ]; then 113 | dd if=${DECRYPTED_FILE} of=${DECRYPTED_FILE}.stripped bs=1 skip=${gzip_index} 114 | mv ${DECRYPTED_FILE}.stripped ${DECRYPTED_FILE} 115 | fi 116 | 117 | tar -xzvf "$DECRYPTED_FILE" -C "$EXTRACT_DIR" 118 | check_success "Extraction" 119 | 120 | # Step 5: Modify the necessary files in the backup 121 | SHADOW_FILE="$EXTRACT_DIR/etc/shadow" 122 | 123 | # Ensure the shadow file exists 124 | if [ ! -f "$SHADOW_FILE" ]; then 125 | echo "Error: Shadow file '$SHADOW_FILE' does not exist in the backup." 126 | exit 1 127 | fi 128 | 129 | # Update the root password hash in the shadow file 130 | echo "Step 5: Setting new root password hash..." 131 | PASSWORD_HASH=$(grep "^admin:" "$SHADOW_FILE" | cut -f 2 -d:) 132 | 133 | # check if macos 134 | if [[ "$OSTYPE" == "darwin"* ]]; then 135 | sed -i '' "s|^root:[^:]*:|root:${PASSWORD_HASH}:|" "$SHADOW_FILE" 136 | else 137 | sed -i "s|^root:[^:]*:|root:${PASSWORD_HASH}:|" "$SHADOW_FILE" 138 | fi 139 | check_success "Updating root password hash" 140 | 141 | echo "Step 6: Configuring /etc/firewall.user to start dropbear..." 142 | FIREWALL_FILE="$EXTRACT_DIR/etc/firewall.user" 143 | echo 'dropbear -p 0.0.0.0:22' > "$FIREWALL_FILE" 144 | check_success "Creating firewall.user for dropbear" 145 | 146 | # Step 7: Repackage the modified backup 147 | echo "Step 7: Repackaging the modified backup..." 148 | tar -czvf "$MODIFIED_TAR" -C "$EXTRACT_DIR" . 149 | check_success "Repackaging" 150 | 151 | # Step 8: Re-encrypt the modified backup 152 | echo "Step 8: Re-encrypting the modified backup..." 153 | openssl enc -pbkdf2 -in "$MODIFIED_TAR" -out "$MODIFIED_TAR_ENC" -e -aes256 -k "/etc/server.key" 154 | check_success "Re-encryption" 155 | 156 | # Step 9: Uploading modified configuration 157 | echo "Step 9: Uploading modified configuration..." 158 | curl "https://${DEVICE_IP}/WCGI" \ 159 | -H "Authorization: Bearer ${AUTH_TOKEN}" \ 160 | -H "Cookie: cSupport=1; sysauth=${COOKIE}" \ 161 | -F restoreFile=@${MODIFIED_TAR_ENC} \ 162 | -F fileUpload=yes -F method=setRestoreSettings \ 163 | --insecure >curl.output 164 | 165 | check_json_success "Restore configuration" 166 | 167 | # Step 10: Cleanup temporary files 168 | echo "Step 10: Cleaning up temporary files..." 169 | rm -rf "$DECRYPTED_FILE" "$EXTRACT_DIR" "$MODIFIED_TAR" curl.output 170 | 171 | # Final Instructions 172 | echo "All steps completed successfully!" 173 | -------------------------------------------------------------------------------- /instructions/Understanding-Workings-Of-TR069.md: -------------------------------------------------------------------------------- 1 | ⚠️ Note: This is a general guide which explains how tr069 works, might contain wrong info and we are not liable for anything you do with it. 2 | 3 | --- 4 | ### IT IS PURELY FOR EDUCATIONAL PURPOSES. YOU ARE REPONSIBLE FOR YOUR DOINGS. WE WONT BE HELD LIABLE FOR ANY DAMAGES DONE TO YOUR DEVICES. 5 | 6 | --- 7 | ## Note from Author: 8 | *This guide will along the way will contain mostly explanations and sometimes codes. Don't ask for help if you cant read. Be your own guide and Use the search engines bestowed upon you to learn more about these things. Don't expect to be spoon fed. 9 | If you manage to do something cool with this info don't feel shy to show us, would love to hear about your hacks🥂* :) 10 | 11 | --- 12 | 13 | 14 | ### A Brief Overview: IDU Firmware Updates & TR-069 15 | 16 | Let’s keep it concise. 17 | 18 | Yes, firmware behaviour varies slightly across models—each may use different binaries for updating. 19 | **Key point**: check your IDU and inspect the `/tmp` directory. If you find files named `jioCwmpLog` there, you're in luck. 20 | 21 | These files log **unencrypted commands and URLs** sent over-the-air to the IDU during firmware updates. 22 | We leverage these logs to capture relevant data whenever the ACS pushes an update. 23 | 24 | ## ⚠️ Keep in Mind 25 | 26 | - You **cannot force** the ACS to push firmware unless it has already been uploaded and made available for download by the CPE. 27 | - You **can** periodically pull the log to a separate location. 28 | - Optionally, implement a script to **drop the ACS connection** by modifying firewall rules as soon as a firmware URL prefix like: http://fota.slv.kai.jiophone.net/5G/ is detected in the log. 29 | 30 | There are experimental approaches too—such as injecting a modified `libssl` to decrypt HTTPS traffic. 31 | While the modified `libssl` is ready, this method is overkill for now :) 32 | 33 | --- 34 | 35 | ## ODU Side (Outdoor Unit) 36 | 37 | The ODU communicates with the ACS similarly and stores unencrypted TR-069/CWMP logs on its filesystem. 38 | However, **without shell access**—which is restricted on most ODUs—this data isn't easily accessible. 39 | 40 | For those with **root shell access**, ACS links can be extracted. 41 | 42 | #### 🔍 Log Files (Located in `/data`) 43 | 44 | - `tr69_stack.log` 45 | - `tr69data.log` 46 | 47 | 📁 These files contain **plaintext TR-069 communication data**. 48 | 49 | #### 🔄 Manually Restart TR-069 on the ODU 50 | 51 | 1. Find the PID of the TR-069 process: 52 | 53 | ```sh 54 | ps aux | grep -e tr 55 | ``` 56 | 57 | 2. Kill it 58 | ```shell 59 | kill -9 60 | ``` 61 | 62 | 3. Restart Tr069 client 63 | ```shell 64 | /usr/bin/tr69_ctrl /usr/bin/tr69c 65 | ``` 66 | 67 | ### Understanding the URL Formats 68 | 69 | - `/5G/` — constant segment; appears in all URLs. 70 | - `/UDI/` — stands for **IDU** firmware (Indoor Unit). 71 | - `/UDO/` — stands for **ODU** firmware (Outdoor Unit). 72 | - `/DIN520/` — indicates the ODU variant; "520" typically matches the beginning of the ODU model number. 73 | - `/A1402_32_S/` — firmware version: 74 | - `2_32_S` is the actual version. 75 | - `A140` encodes part of the model in reverse — e.g., `A140` → `041A`, which hints at model suffix like `52041`. 76 | - `/Sxxxxxxx.img` — the actual firmware file: 77 | - File name usually starts with `S`, followed by a seemingly random string (likely hashed or auto-generated). 78 | 79 | 80 | 81 | 82 | ## TR-069 Communication – IDU 83 | 84 | ### 🛠️ Server Configuration 85 | 86 | - **ACS Server**: `https://acs.oss.jio.com:8443/ftacs-digest/ACS` 87 | - To find your ACS server, check: 88 | - `/etc/cpestate-default.xml` – (in SSH-enabled IDU) 89 | - `/rom/etc/cpestate-default.xml` – (alternate path) 90 | - `/etc/keep/config.save` – (from firmware backup) 91 | - **Communication Port**: `7547` (TCP) 92 | - **Authentication**: HTTPS with Digest Authentication 93 | 94 | --- 95 | 96 | ### 🔁 Initial Connection 97 | 98 | - Device sends **periodic inform messages** every 24 hours. 99 | - Connection settings stored in: 100 | - `/etc/cpestate-default.xml` 101 | - **TR-069 client binary**: 102 | - `/sbin/cwmpc` 103 | - Includes key device info: 104 | - Model, serial number, firmware version 105 | - Secured via **HTTPS Digest Authentication** 106 | 107 | --- 108 | 109 | ### 📦 Device Information Sent 110 | 111 | > Collected from various system files: 112 | 113 | - **Model name**: `/tmp/deviceModel` 114 | - **Manufacturer**: `/tmp/mfgName` 115 | - **Serial number**: `/tmp/deviceSerial` 116 | - **Hardware version**: `/tmp/hwVersion` 117 | - **Software version**: (current firmware version) 118 | - **OUI**: First 6 characters of MAC address 119 | 120 | --- 121 | 122 | ## 📥 Firmware Download Process 123 | 124 | ### 1. 🔔 Update Notification 125 | 126 | - ACS server detects available firmware and sends a `Download` RPC. 127 | - RPC contains: 128 | - Firmware download URL 129 | - Signature file URL 130 | - Auth credentials (if required) 131 | - File size information 132 | - All communication is encrypted via **HTTPS** 133 | 134 | --- 135 | 136 | ### 2. ⬇️ Download Phase 137 | 138 | - TR-069 client (`/sbin/cwmpc`) receives the `Download` RPC. 139 | - Downloads: 140 | - Firmware to `/tmp/firmware.img` 141 | - Signature to `/tmp/firmware.sig` 142 | - **These filenames are mandatory** for the upgrade process. 143 | - Files are verified for: 144 | - **Integrity** 145 | - **Completeness** 146 | 147 | --- 148 | 149 | ### 3. ✅ Validation Phase 150 | 151 | ```sh 152 | /sbin/jioSysMethods.sh validate /tmp/firmware.img /tmp/firmware.sig 153 | ``` 154 | 155 | - Valid trigger sources: 156 | - `GUI`: For web interface-triggered upgrades 157 | - `ACS`: For TR-069 / Auto Configuration Server-triggered upgrades 158 | - `PLATFORM`: For system/platform-triggered upgrades 159 | - `PLUME`: For Plume mesh-triggered upgrades 160 | 161 | 162 | - Performs: 163 | - File existence and name checks 164 | - Cryptographic signature validation 165 | - Device compatibility verification 166 | 167 | ### 4. 🔐Cryptographic Verification 168 | 169 | - Uses `/usr/bin/jcrypt upgrade` for verification 170 | - Takes 3 parameters: 171 | - Device model (from `/tmp/deviceModel`) 172 | - Signature file path 173 | - Firmware image path 174 | - Verification is model-specific 175 | - Uses asymmetric cryptography: 176 | - Private key held by FW-maker 177 | - Public key embedded in device 178 | - Signature is created with private key 179 | - Verification is done with public key 180 | 181 | ### 5.🗃️ File needed to be present during a fw upgrade 182 | - Firmware image: `/tmp/firmware.img` 183 | - Signature file: `/tmp/firmware.sig` 184 | - Device model: `/tmp/deviceModel` 185 | - Hardware version: `/tmp/hwVersion` 186 | - Manufacturer: `/tmp/mfgName` 187 | - Serial number: `/tmp/deviceSerial` -------------------------------------------------------------------------------- /instructions/List-OF-IDU's-and-ODU's.md: -------------------------------------------------------------------------------- 1 | 2 | Note: This list is still under review, the information in this table maybe be inaccurate to some extent. 3 | 4 | # 📦 List of IDUs 5 | 6 | | Model | Manufacturer | Firmware Prefix | Bootloader Access | DebugPorts | RootAccess | Openwrt_version | Known Issues ? | 7 | | ------- | ----------------------------- | ------------------ | ----------------- | ---------- | ---------- | --------------- | ------------------------------------------------------- | 8 | | IDU6101 | Arcadyan (MTK7621) | ARCNJIO_JIDU6101_R | ✅ | uart | ✅ | 21.02-SNAPSHOT | 160mhz wont work on fw v2.0.9 | 9 | | IDU6801 | GMOB | GMOBJIO_JIDU6801_R | ✅ | uart | ✅ | 21.02-SNAPSHOT | 160mhz wont work on fw v2.0.9 | 10 | | IDU6601 | SPED | SPEDJIO_JIDU6601_R | ✅ | uart | ✅ | 21.02-SNAPSHOT | 160mhz wont work on fw v2.0.9 | 11 | | IDU6401 | Sercomm | SRCMJIO_JIDU6401_R | ✅ | uart | ✅ | 21.02-SNAPSHOT | 160mhz wont work on fw v2.0.9 | 12 | | IDU6701 | Skyworth | SKYWJIO_JIDU6701_R | ✅ | uart | ✅ | 21.02-SNAPSHOT | 160mhz wont work on fw v2.0.9 | 13 | | IDU6811 | Telpa | JIO_JIDU6J11_R | ❓ | uart | ✅ | 19.07-SNAPSHOT | Some users faced setting not persisting across reboots. | 14 | | IDU6111 | Arcadyan (IPQ9574/AP-AL02-C1) | JIO_JIDU6J11_R | ❓ | uart | ✅ | 19.07-SNAPSHOT | LOCKED after fw >R.09 | 15 | 16 | # 📡 List of ODUs 17 | | Model | Manufacturer / Assembler | Module Used | Firmware_release | DebugPorts | RootAccess | Extra Info | 18 | | --------- | ----------------------------- | ----------------- | ------------------------ | -------------------------------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | 19 | | JODU51641 | ❓ Unknown | ❓ Unknown | TBD | uart❓ usb❓ | Not yet, Unconfirmed❓ | | 20 | | JODU51642 | sercomm | COMPAL/NXP | TBD | uart❓ usb✅(Only fastboot) | No❌, fastboot only device | Fastboot is persistent for an entire boot duration if triggered correctly using hw reset btn. Device is bootloader unlocked. | 21 | | JODU51643 | ❓ | ❓ | ❓ | ❓ | ❓ | | 22 | | JODU51741 | GeneralMobile | RG520F-JO(SDX65) | TBD | uart❓ usb✅(exposes only fastboot) | No❌, fastboot only device | Device is bootloader unlocked, flashing is possible. | 23 | | JODU52040 | Askey | RG500Q-EA (SDX55) | JODU52040_REL_07_27_00_S | uart✅(Password Locked) usb✅(Full adb shell access) | yes✅, via usb -> adb -> ssh | FW is full readonly, kernel lacks overlayfs support, ssh access isn't persistent. | 24 | | JODU52041 | Askey | RG500Q-EA(SDX65) | JODU52041_REL_02_32_00_S | uart✅(Password Locked) usb✅(Full adb shell access) | yes✅, via usb -> adb -> ssh | Same as above. LOCKED on latest fw | 25 | | JODU52121 | LUXSHARE | | JODU52121_REL_01_15_00_S | uart❓ usb❓ | Not yet, Unconfirmed❓ | | 26 | | JODU52140 | SPPEDTECH / NEOLYNC / LUXSLAM | RG520F-JO(SDX65) | TBD | uart✅ usb❌(doesn’t expose any port) | No❌, uart console locked | LOCKED on latest FW | 27 | | JODU52240 | Arcadyan | RG520F-JO(SDX65) | TBD | uart❓ usb❓ | Not yet, Unconfirmed❓ | Latest FW updates have disabled the web UI abilities. | 28 | | JODU52540 | | | JODU52540_REL_25_01_05_S | uart❓ usb❓ | Not yet, Unconfirmed❓ | | 29 | #### TBD: To be determined yet 30 | 31 | 32 | ## Firmware links 33 | 34 | | Firmware ID | V2.0.9 | V2.0.16 | 35 | | ------------------ | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | 36 | | ARCNJIO_JIDU6101_R | [Download](https://mega.nz/file/q9oURIQb#--QU1QC0MsjTGuY_jh0NIB0XVuEL5Qh7fsrgT34bGCM) | | 37 | | GMOBJIO_JIDU6801_R | [Download](https://mega.nz/file/fhJi3BiZ#Dp_WtubqyFGhrk33rYGgdKgQUw7ax0FmUHaisNYmyd8) | [Download](https://mega.nz/folder/31YTlSbI#Ar-aQK605GZqI_1zc_PZtw) | 38 | | SPEDJIO_JIDU6601_R | [Download](https://mega.nz/file/T5g03aLZ#AGr7fBJDbpa0dLXrL-bAdALjEBgAT1wVzL7ncA0RJq8) | | 39 | | SRCMJIO_JIDU6401_R | [Download](https://mega.nz/file/Pkh0SbpB#kBpW7ls7Y2GJ7Y47DmgzzHNd-OCBSEBUoMblwyovp_E) | | 40 | | SKYWJIO_JIDU6701_R | [Download](https://mega.nz/file/LgYkUTBJ#btKP77FlbvokfYR0mmBQCQEtCoLaAkIqjt7SpdKoiBI) | | 41 | 42 | | Firmware ID | Links | Notes | 43 | | ------------------------ | ------------------------------------------------------------------------------------- | ------------------------ | 44 | | JODU52041_REL_02_32_00_S | [Download](https://mega.nz/file/nsAwwDjT#Tme3W2k8VCRAB7b99L1wI0NVxwrBHB0_bJ51Ck2i0JQ) | ❌Locked FW, DO NOT FLASH | 45 | -------------------------------------------------------------------------------- /instructions/JAF-IDU-LuCI-Install-Guide.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | 4 | # Installing LuCI on JAF IDU 5 | 6 | *Disclaimer: This is ONLY for educational purposes. No one is responsible for any type of damage. Proceed at your own risk.* 7 | 8 | **⚠️ WARNING: Perform Step 0 first. If you accidentally fill up the storage, your only option will be to reset the router. If the installation fails midway, you will likely encounter a *500 Internal Server Error* and won’t be able to reset the router via the web UI. Your only recovery options will be the physical reset button or [Resetting the router via SSH](JAF-IDU-Reset-Via-SSH.md).** 9 | 10 | --- 11 | 12 | ## Step 0: Expand Storage 13 | 14 | * This step is necessary because the internal storage is very limited. 15 | * Expand the root filesystem using a USB overlay (no safer method found that doesn’t risk the router). 16 | * Follow [this official guide](https://openwrt.org/docs/guide-user/additional-software/extroot_configuration) **carefully**. 17 | * Reboot the device and run `df -h`. If you see your USB drive mounted at `/`, you're good to go. 18 | * If you encounter errors, check the [Troubleshooting](#troubleshooting) section. 19 | 20 | --- 21 | 22 | ## Step 1: Clean up OPKG Feeds 23 | 24 | * Update the OPKG feeds. 25 | * The default OPKG feeds include many dead links used during production that now throw warnings during `opkg update`. 26 | * To fix this, use any editor (we’ll use `vi`) to clean up the distfeeds. 27 | * Open the file: 28 | 29 | ```sh 30 | vi /etc/opkg/distfeeds.conf 31 | ``` 32 | * Disable dead links and keep only valid OpenWrt ones. Below is an example for a MediaTek-based router running OpenWrt 22.02 snapshot and OpenWrt 19.07 snapshot. Modify your distfeeds accordingly. 33 | 34 | **Example of a clean distfeed (22.02):** 35 | 36 | ```sh 37 | src/gz openwrt_base https://downloads.openwrt.org/releases/21.02-SNAPSHOT/packages/aarch64_cortex-a53/base 38 | src/gz openwrt_luci https://downloads.openwrt.org/releases/21.02-SNAPSHOT/packages/aarch64_cortex-a53/luci 39 | src/gz openwrt_packages https://downloads.openwrt.org/releases/21.02-SNAPSHOT/packages/aarch64_cortex-a53/packages 40 | src/gz openwrt_routing https://downloads.openwrt.org/releases/21.02-SNAPSHOT/packages/aarch64_cortex-a53/routing 41 | src/gz openwrt_telephony https://downloads.openwrt.org/releases/21.02-SNAPSHOT/packages/aarch64_cortex-a53/telephony 42 | ``` 43 | 44 | **Example of a clean distfeed (19.07):** 45 | ```sh 46 | src/gz openwrt_base https://archive.openwrt.org/releases/19.07.9/packages/arm_cortex-a7_neon-vfpv4/base 47 | src/gz openwrt_freifunk https://archive.openwrt.org/releases/19.07.9/packages/arm_cortex-a7_neon-vfpv4/freifunk 48 | src/gz openwrt_luci https://archive.openwrt.org/releases/19.07.9/packages/arm_cortex-a7_neon-vfpv4/luci 49 | src/gz openwrt_packages https://archive.openwrt.org/releases/19.07.9/packages/arm_cortex-a7_neon-vfpv4/packages 50 | src/gz openwrt_routing https://archive.openwrt.org/releases/19.07.9/packages/arm_cortex-a7_neon-vfpv4/routing 51 | src/gz openwrt_telephony https://archive.openwrt.org/releases/19.07.9/packages/arm_cortex-a7_neon-vfpv4/telephony 52 | ``` 53 | 54 | 55 | --- 56 | 57 | ## Step 2: Uninstall Existing LuCI Components 58 | 59 | *Note: During reinstallation, a package named `libnl-tiny2022-11-01` may cause a conflict. **DO NOT UNINSTALL IT.** The conflict arises because two packages serve similar purposes. The original package has many dependencies, so it's safer to overwrite it.* 60 | 61 | ```sh 62 | opkg remove --force-depends \ 63 | liblucihttp-lua \ 64 | liblucihttp0 \ 65 | luci \ 66 | luci-app-firewall \ 67 | luci-app-opkg \ 68 | luci-base \ 69 | luci-compat \ 70 | luci-lib-base \ 71 | luci-lib-ip \ 72 | luci-lib-jsonc \ 73 | luci-lib-nixio \ 74 | luci-mod-admin-full \ 75 | luci-mod-network \ 76 | luci-mod-status \ 77 | luci-mod-system \ 78 | luci-proto-ipv6 \ 79 | luci-proto-ppp \ 80 | luci-ssl-openssl \ 81 | luci-theme-bootstrap \ 82 | rpcd-mod-luci 83 | ``` 84 | 85 | --- 86 | 87 | ## Step 3: Reinstall LuCI 88 | 89 | ```sh 90 | opkg update 91 | opkg install --force-overwrite luci 92 | ``` 93 | 94 | You may receive this warning (ignore it if it doesn’t appear): 95 | 96 | ```sh 97 | Collected errors: 98 | * resolve_conffiles: Existing conffile /etc/config/luci is different from the conffile in the new package. The new conffile will be placed at /etc/config/luci-opkg. 99 | ``` 100 | 101 | To resolve this: 102 | 103 | ```sh 104 | mv /etc/config/luci-opkg /etc/config/luci 105 | ``` 106 | 107 | If successful, your `/www/` directory should contain: 108 | 109 | ```sh 110 | cgi-bin index.html luci-static 111 | ``` 112 | 113 | * The default `uhttpd` server command will also launch the new LuCI interface. 114 | * Access LuCI: [https://192.168.31.1/cgi-bin/luci/](https://192.168.31.1/cgi-bin/luci/) 115 | * The LuCI password will be the same as your SSH password. 116 | 117 | --- 118 | 119 | ## Note 120 | 121 | ~~Many features do not work in the LuCI interface because they have used custom LuCI API endpoints or left some features unimplemented. These may or may not be fixed in the future (someone needs to invest time fixing the mess).~~ 122 | 123 | --- 124 | 125 | ### Hotfix for Broken CGI API Endpoints 126 | 127 | Fixes: System Logs, Software, Firewall, Backup/Restore/Flash pages in LuCI. 128 | 129 | ```sh 130 | opkg update 131 | opkg install cgi-io 132 | ``` 133 | 134 | ```sh 135 | cd /www/cgi-bin 136 | ln -s ../../usr/libexec/cgi-io cgi-backup 137 | ln -s ../../usr/libexec/cgi-io cgi-download 138 | ln -s ../../usr/libexec/cgi-io cgi-exec 139 | ln -s ../../usr/libexec/cgi-io cgi-upload 140 | ``` 141 | 142 | **Working features in LuCI:** 143 | 144 | * Technically everything, except those controlled by OpenSync. Disabling OpenSync is possible but should be done with caution, as you will need to manually configure Wi-Fi management, DNS resolution, uplink, etc.—all of which are part of the OpenSync management layer. 145 | 146 | --- 147 | 148 | ## Bonus 149 | 150 | * Use `btop` for a modern CLI-based resource monitor. You can compile it yourself or use the precompiled version by @BlueNecko. 151 | 152 | Link: [https://drive.google.com/drive/folders/1Om93J8oUOOn1MDMKNvqpbZeXX\_Mmn0FK?usp=sharing](https://drive.google.com/drive/folders/1Om93J8oUOOn1MDMKNvqpbZeXX_Mmn0FK?usp=sharing) 153 | 154 | --- 155 | 156 | ## Troubleshooting 157 | 158 | If the USB overlay isn’t activating on boot, follow these steps. First, check the `dmesg` output and look for `extroot`. 159 | 160 | ### extroot-not-configured 161 | 162 | * This usually means your configuration is invalid. 163 | * Run: 164 | 165 | ```sh 166 | cat /etc/config/fstab 167 | ``` 168 | * Ensure `rwm` and `extroot` entries exist with a unique UUID and a line like: 169 | 170 | ```sh 171 | option target '/overlay' 172 | ``` 173 | * Example configuration: 174 | ![extroot\_fstab\_config.png](../assets/IDU_extroot_fstab_config.png) 175 | 176 | ### ubiblock0\_1 not found 177 | 178 | * This error usually indicates the need to reflash the stock firmware. 179 | * Download the firmware from: [https://small.fileditchstuff.me/s18/TGJFgrgUrrolDsBKDatu.tar.gz](https://small.fileditchstuff.me/s18/TGJFgrgUrrolDsBKDatu.tar.gz) 180 | * Extract the archive, flash the appropriate firmware, and retry the extroot setup. 181 | 182 | 183 | --------------------------------------------------------------------------------