Skip to content

Instantly share code, notes, and snippets.

@Geofferey
Last active June 7, 2025 08:01
Show Gist options
  • Save Geofferey/d105ce5e2b4c557e8fb3003dafd448eb to your computer and use it in GitHub Desktop.
Save Geofferey/d105ce5e2b4c557e8fb3003dafd448eb to your computer and use it in GitHub Desktop.
ttlset.sh from Inseego Tool modified for use outside of tookkit
#!/bin/sh
## This script was originally part of the Inseego Tool
# Script supplies methods to spoof/set TTL+DPI+IMEI
# I did not write this script but I am using it as part
# of a larger set of modifications to the Inseego M2000B
# Script version
script_version="1.4.4"
download_url="gist.githubusercontent.com/Geofferey/d105ce5e2b4c557e8fb3003dafd448eb/raw/inseegokit.sh"
# Log file path
log_file="/tmp/inseegokit.log"
web_root="/data/var/www"
hstk_load_file="/tmp/hstk_last_load"
# Set the library path to include the directory where libwatchdog_api.so is located
LD_LIBRARY_PATH="/opt/nvtl/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export LD_LIBRARY_PATH
# Ensure the script can find the modem2_cli command
PATH="${PATH}${PATH:+:}/opt/nvtl/bin"
export PATH
# Function to log messages (POSIX-compliant)
log_message() {
timestamp=$(date '+%Y-%m-%d %H:%M:%S') # Portable date format
printf "%s - %s\n" "$timestamp" "$1" >> "$log_file"
printf "%s\n" "$1"
}
# Function to check for and apply script updates
check_for_updates() {
# URL to download the latest script
download_url="https://gist.githubusercontent.com/Geofferey/d105ce5e2b4c557e8fb3003dafd448eb/raw/inseegokit"
log_message "Checking for script updates..."
# Download the script to a temporary file (POSIX-safe temp file)
tmpfile="/tmp/inseegokit_update_$$"
wget -q "$download_url" -O "$tmpfile" 2>/dev/null
if [ $? -ne 0 ]; then
log_message "Error: Failed to download the updated script."
rm -f "$tmpfile"
return 1
fi
# Extract the version from the downloaded script (POSIX-compliant)
latest_version=$(sed -n 's/^script_version="\([^"]*\)"/\1/p' "$tmpfile")
if [ -z "$latest_version" ]; then
log_message "Error: Could not determine version of the downloaded script. Aborting update."
rm -f "$tmpfile"
return 1
fi
log_message "Downloaded script version: $latest_version"
# Compare with the current version
if [ "$latest_version" != "$script_version" ]; then
log_message "New version available: $latest_version. Updating script..."
# Replace the current script with the new version
mv "$tmpfile" "$0"
chmod +x "$0"
log_message "Script updated to version $latest_version. Restarting..."
exec "$0" "$@"
else
log_message "Script is already up to date (version $script_version)."
rm -f "$tmpfile"
fi
}
log_imsi() {
# Load auto_mode from config file, default to 'yes' if not set
config_file="/data/etc/ttl.conf"
auto_mode=$(grep '^auto_mode=' "$config_file" 2>/dev/null | cut -d'=' -f2)
#auto_mode=${auto_mode:-no} # Default to auto mode if unset
log_message "Auto Mode is set to auto_mode=${auto_mode}"
if [ ${auto_mode} = 'yes' ]; then
active_imsi=$(modem2_cli get_imsi | grep -w "imsi :" | cut -d ':' -f2 | cut -d ' ' -f2 2>/dev/null)
else
unset active_imsi
fi
if [[ ${auto_mode} = "yes" ]] && [[ -z "$active_imsi" ]]; then
log_message "IMSI: Unable to retrieve active IMSI"
carrier="Unknown"
fi
if [[ ${auto_mode} = "yes" ]] && [[ ! -z "$active_imsi" ]]; then
log_message "IMSI: $active_imsi"
# Extract MCC (first 3 digits) and MNC (next 2-3 digits)
mcc="${active_imsi:0:3}"
mnc="${active_imsi:3:3}" # Some carriers use 2 or 3 digits for MNC
# Determine Carrier Based on MCC-MNC
case "$mcc$mnc" in
## T-Mobile MNCs
310260|310160|310200|310210|310220|310230|310240|310250|310270|310310|310490|311660)
carrier="T-Mobile"
default_ttl_value=65
default_hl_value=64
;;
## Verizon MNCs
311480|310012|311270|310590|310890|311272|310980|311273|311271|312530)
carrier="Verizon"
default_ttl_value=65 # Updated to 65 for tethering
default_hl_value=64 # Updated to 64 for standard IPv6
;;
## AT&T MNCs
310410|310150|310170|310380|310980)
carrier="AT&T"
default_ttl_value=64
default_hl_value=64
;;
## Dish Wireless MNCs
311490|312530|312770)
carrier="Dish Wireless"
default_ttl_value=64
default_hl_value=64
;;
## Total Wireless (Verizon MVNO - MNC 118 or 88)
311180|310118|311088|310088)
carrier="Total Wireless"
default_ttl_value=118
default_hl_value=255
;;
## Visible (Different TTL from Verizon)
311480|311272|311271|310012)
carrier="Visible"
default_ttl_value=66
default_hl_value=255
;;
## Default case for unknown carriers
*)
carrier="Unknown"
default_ttl_value=65 # Generic Safe Defaults
default_hl_value=64
;;
esac
log_message "Detected Carrier: $carrier (MCC: $mcc, MNC: $mnc)"
fi
# Set TTL/HL values based on auto_mode
if [ "$auto_mode" = "yes" ]; then
# In auto mode, use carrier defaults only if no manual values are set
new_ttl_value=${new_ttl_value:-$default_ttl_value}
new_hl_value=${new_hl_value:-$default_hl_value}
log_message "Auto mode: Using carrier defaults (TTL: $new_ttl_value, HL: $new_hl_value) unless overridden"
else
# In manual mode, do not override existing values with any defaults
if [ -z "$new_ttl_value" ] || [ -z "$new_hl_value" ]; then
log_message "Manual mode: No manual TTL/HL values set, falling back to generic defaults"
new_ttl_value=
new_hl_value=
else
log_message "Manual mode: Using pre-set TTL: $new_ttl_value, HL: $new_hl_value"
fi
fi
}
check_interface() {
iface="$1"
if [ -e "/sys/class/net/$iface" ]; then
log_message "Interface $iface found in /sys/class/net"
return 0
elif [ -e "/dev/$iface" ]; then
log_message "Interface $iface found in /dev"
return 0
else
return 1
fi
}
# Function to set TTL & HL values and apply iptables rules
apply_ttl_mod() {
log_message "Applying iptables rules"
# Retrieve IMSI and determine carrier-specific TTL/HL defaults
log_imsi
# Override only if ttlvol/hlvol exist and are non-empty
if [ -s /data/etc/ttlvol.conf ]; then
new_ttl_value=$(cat /data/etc/ttlvol.conf)
fi
if [ -s /data/etc/hlvol.conf ]; then
new_hl_value=$(cat /data/etc/hlvol.conf)
fi
# Ensure TTL and HL values are correctly set
log_message "Final TTL setting: $new_ttl_value"
log_message "Final HL setting: $new_hl_value"
# Define interfaces
rmnet_interfaces="rmnet_data0 rmnet_data1 rmnet_data2 rmnet_data3 rmnet_data4 rmnet_data5"
eth0_interface="eth0"
wlan0_interface="wlan0"
wlan1_interface="wlan1"
# Remove existing iptables rules
for interface in $rmnet_interfaces $eth0_interface $wlan0_interface $wlan1_interface; do
if check_interface "$interface"; then
iptables -t mangle -D POSTROUTING -o "$interface" ! -p icmp -j TTL --ttl-set "$new_ttl_value" 2>/dev/null
iptables -t mangle -D PREROUTING -i "$interface" -j TTL --ttl-set "$new_ttl_value" 2>/dev/null
ip6tables -t mangle -D POSTROUTING -o "$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "$new_hl_value" 2>/dev/null
ip6tables -t mangle -D PREROUTING -i "$interface" -j HL --hl-set "$new_hl_value" 2>/dev/null
fi
done
# Apply new iptables rules dynamically per carrier
rmnet_interfaces=$(ip -o link show | grep -E 'rmnet_data[0-9]+@' | grep 'UP' | cut -d':' -f2 | cut -d'@' -f1 | tr -d ' ' || true)
if [ -n "$rmnet_interfaces" ]; then
for interface in $rmnet_interfaces; do
if check_interface "$interface"; then
# IPv4 TTL
iptables -t mangle -I POSTROUTING -o "$interface" ! -p icmp -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || \
log_message "Failed to set IPv4 POSTROUTING TTL for $interface"
iptables -t mangle -I PREROUTING -i "$interface" -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || \
log_message "Failed to set IPv4 PREROUTING TTL for $interface"
# IPv6 HL
ip6tables -t mangle -I POSTROUTING -o "$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "$new_hl_value" 2>/dev/null || \
log_message "Failed to set IPv6 POSTROUTING HL for $interface"
ip6tables -t mangle -I PREROUTING -i "$interface" -j HL --hl-set "$new_hl_value" 2>/dev/null || \
log_message "Failed to set IPv6 PREROUTING HL for $interface"
log_message "iptables rules applied for interface $interface"
printf "iptables rules applied for interface %s\n" "$interface"
else
log_message "Interface $interface not found or down, skipping"
fi
done
else
log_message "No active rmnet_data interfaces found � applying fallback TTL/DPI rules (not bound to any interface)"
# Fallback: Apply rules without interface matching
iptables -t mangle -I POSTROUTING ! -p icmp -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || \
log_message "Failed to set fallback IPv4 POSTROUTING TTL"
iptables -t mangle -I PREROUTING -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || \
log_message "Failed to set fallback IPv4 PREROUTING TTL"
ip6tables -t mangle -I POSTROUTING ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "$new_hl_value" 2>/dev/null || \
log_message "Failed to set fallback IPv6 POSTROUTING HL"
ip6tables -t mangle -I PREROUTING -j HL --hl-set "$new_hl_value" 2>/dev/null || \
log_message "Failed to set fallback IPv6 PREROUTING HL"
log_message "Fallback TTL and HL rules applied (not interface-specific)"
fi
for interface in $eth0_interface $wlan0_interface $wlan1_interface; do
if check_interface "$interface"; then
iptables -t mangle -I POSTROUTING -o "$interface" ! -p icmp -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || log_message "Failed to set IPv4 POSTROUTING TTL for $interface"
ip6tables -t mangle -I POSTROUTING -o "$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "$new_hl_value" 2>/dev/null || log_message "Failed to set IPv6 POSTROUTING HL for $interface"
log_message "iptables rules applied for interface $interface"
printf "iptables rules applied for interface %s\n" "$interface"
else
log_message "Interface $interface not found or down, skipping"
fi
done
}
remove_iptables_rules() {
log_message "Removing all iptables rules"
rmnet_interfaces="rmnet_data0 rmnet_data1 rmnet_data2 rmnet_data3 rmnet_data4 rmnet_data5"
eth0_interface="eth0"
wlan0_interface="wlan0"
wlan1_interface="wlan1"
# Assume new_ttl_value and new_hl_value are set globally or passed; log if unset
if [ -z "$new_ttl_value" ] || [ -z "$new_hl_value" ]; then
log_message "Warning: TTL or HL value is empty, removal may be incomplete."
fi
# Remove iptables rules for all interfaces with checking
for interface in $rmnet_interfaces $eth0_interface $wlan0_interface $wlan1_interface; do
if check_interface "$interface"; then
iptables -t mangle -D POSTROUTING -o "$interface" ! -p icmp -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || log_message "Failed to remove IPv4 POSTROUTING TTL for $interface"
ip6tables -t mangle -D POSTROUTING -o "$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "$new_hl_value" 2>/dev/null || log_message "Failed to remove IPv6 POSTROUTING HL for $interface"
# Only rmnet interfaces have PREROUTING rules
case "$interface" in
rmnet_data*)
iptables -t mangle -D PREROUTING -i "$interface" -j TTL --ttl-set "$new_ttl_value" 2>/dev/null || log_message "Failed to remove IPv4 PREROUTING TTL for $interface"
ip6tables -t mangle -D PREROUTING -i "$interface" -j HL --hl-set "$new_hl_value" 2>/dev/null || log_message "Failed to remove IPv6 PREROUTING HL for $interface"
;;
esac
else
log_message "Interface $interface not found, skipping removal"
fi
done
log_message "All iptables rules removed"
}
log_imei() {
imei=$(modem2_cli get_info 2>/dev/null | sed -n 's/.*imei:.*\[\([^]]*\)\].*/\1/p')
if [ -z "$imei" ]; then
log_message "IMEI: Unable to retrieve IMEI"
else
log_message "IMEI: $imei"
fi
}
start_http_server() {
mkdir -p "$web_root/cgi-bin"
cat <<INDEX_EOF > "$web_root/index.html"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Device Management</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
min-height: 100vh;
margin: 0;
background-color: #000000;
}
.sidebar {
width: 250px;
background-color: #333;
color: white;
padding: 15px;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
}
.sidebar a {
color: white;
text-decoration: none;
display: block;
padding: 10px 0;
margin: 5px 0;
}
.sidebar a:hover {
background-color: #575757;
}
.main-content {
flex: 1;
padding: 20px;
}
h1, h2 {
color: #333;
}
.form-group {
margin: 15px 0;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input, .form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
button {
background-color: #9e42fd;
color: white;
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.section {
display: none;
}
.section.active {
display: block;
}
.info-output {
background-color: #fff;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
margin-top: 15px;
white-space: pre-wrap;
}
.band-checkbox-group {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
max-width: 600px;
}
.band-checkbox-group div {
display: flex;
align-items: center;
}
.band-checkbox-group input {
margin-right: 5px;
}
</style>
<script>
function showSection(sectionId) {
var sections = document.querySelectorAll('.section');
for (var i = 0; i < sections.length; i++) {
sections[i].classList.remove('active');
}
document.getElementById(sectionId).classList.add('active');
}
function toggleCustomFields() {
var useAuto = document.getElementById('use_auto').checked;
document.getElementById('custom-fields').style.display = useAuto ? 'none' : 'block';
}
function toggleDpiFields() {
var dpiBlocking = document.getElementById('dpi_blocking').checked;
document.getElementById('dpi-fields').style.display = dpiBlocking ? 'block' : 'none';
}
async function setTtlHl(event) {
event.preventDefault();
var useAuto = document.getElementById('use_auto').checked ? 'yes' : 'no';
var ttl = document.getElementById('ttl').value;
var hl = document.getElementById('hl').value;
var dpiBlocking = document.getElementById('dpi_blocking').checked ? 'yes' : 'no';
var mss = document.getElementById('mss').value;
var response = await fetch('/cgi-bin/set_ttl_hl.sh', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'use_auto=' + useAuto + '&ttl=' + ttl + '&hl=' + hl + '&dpi_blocking=' + dpiBlocking + '&mss=' + mss
});
var data = await response.text();
document.getElementById('ttl-hl-output').innerText = data;
// Refresh displayed values after setting
await fetchCurrentSettings();
}
async function applyTtlHl() {
var response = await fetch('/cgi-bin/apply.sh');
var data = await response.text();
document.getElementById('ttl-hl-output').innerText = data;
}
async function fetchInformation() {
var response = await fetch('/cgi-bin/get_info.sh');
var data = await response.text();
document.getElementById('info-output').innerHTML = data;
}
async function fetchDiagnostics() {
var response = await fetch('/cgi-bin/run_diagnostics.sh');
var data = await response.text();
document.getElementById('diagnostics-output').innerHTML = data;
}
async function reboot() {
fetch('/cgi-bin/reboot.sh');
}
async function adbd() {
fetch('/cgi-bin/adbd.sh');
}
async function fetchBands() {
var response = await fetch('/cgi-bin/get_bands.sh');
var data = await response.text();
document.getElementById('bands-output').innerText = data;
var supportedLteBands = [];
var enabledLteBands = [];
var supportedNr5gBands = [];
var enabledNr5gNsaBands = [];
var enabledNr5gSaBands = [];
var lines = data.split('\n');
var isLte = false;
var isNr5g = false;
var isEnabledLte = false;
var isEnabledNr5gNsa = false;
var isEnabledNr5gSa = false;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
if (line.includes('Supported Bands (LTE)')) {
isLte = true; isNr5g = false; isEnabledLte = false; isEnabledNr5gNsa = false; isEnabledNr5gSa = false;
} else if (line.includes('Supported Bands (5G)')) {
isLte = false; isNr5g = true; isEnabledLte = false; isEnabledNr5gNsa = false; isEnabledNr5gSa = false;
} else if (line.includes('Enabled LTE Bands')) {
isEnabledLte = true; isLte = false; isNr5g = false; isEnabledNr5gNsa = false; isEnabledNr5gSa = false;
} else if (line.includes('Enabled NR5G NSA Bands')) {
isEnabledNr5gNsa = true; isEnabledLte = false; isLte = false; isNr5g = false; isEnabledNr5gSa = false;
} else if (line.includes('Enabled NR5G SA Bands')) {
isEnabledNr5gSa = true; isEnabledNr5gNsa = false; isEnabledLte = false; isLte = false; isNr5g = false;
} else if (line.includes('band[')) {
var band = line.split(': ')[1].replace('[', '').replace(']', '');
if (isLte && band != '0') supportedLteBands.push(band);
else if (isNr5g && band != '0') supportedNr5gBands.push(band);
else if (isEnabledLte && band != '0') enabledLteBands.push(band);
else if (isEnabledNr5gNsa && band != '0') enabledNr5gNsaBands.push(band);
else if (isEnabledNr5gSa && band != '0') enabledNr5gSaBands.push(band);
}
}
function isBandEnabled(band, enabledBands) {
return enabledBands.includes(band);
}
var isFirstRun = enabledLteBands.length === 0 && enabledNr5gNsaBands.length === 0 && enabledNr5gSaBands.length === 0;
var lteContainer = document.getElementById('lte-bands');
lteContainer.innerHTML = supportedLteBands.map(function(band) {
var isChecked = isFirstRun || isBandEnabled(band, enabledLteBands) ? 'checked' : '';
return '<div><input type="checkbox" name="lte-bands" value="' + band + '" ' + isChecked + '> Band ' + band + '</div>';
}).join('');
var nr5gContainer = document.getElementById('nr5g-bands');
nr5gContainer.innerHTML = supportedNr5gBands.map(function(band) {
var isCheckedNsa = isBandEnabled(band, enabledNr5gNsaBands) ? 'checked' : '';
var isCheckedSa = isBandEnabled(band, enabledNr5gSaBands) ? 'checked' : '';
return '<div><input type="checkbox" name="nr5g-nsa-bands" value="' + band + '" ' + isCheckedNsa + '> NSA Band ' + band +
'<input type="checkbox" name="nr5g-sa-bands" value="' + band + '" ' + isCheckedSa + '> SA Band ' + band + '</div>';
}).join('');
}
async function setHomepage(event) {
event.preventDefault();
var homepage = document.getElementById('homepage').value;
var response = await fetch('/cgi-bin/set_homepage.sh', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'homepage=' + encodeURIComponent(homepage)
});
var data = await response.text();
document.getElementById('homepage-output').innerText = data;
}
async function repairImei(event) {
event.preventDefault();
var imei = document.getElementById('imei').value;
var response = await fetch('/cgi-bin/repair_imei.sh', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'imei=' + encodeURIComponent(imei)
});
var data = await response.text();
document.getElementById('imei-output').innerText = data;
}
async function setModeSwitch(event) {
event.preventDefault();
var mode = document.getElementById('mode').value;
var response = await fetch('/cgi-bin/set_mode_switch.sh', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'mode=' + mode
});
var data = await response.text();
document.getElementById('mode-output').innerText = data;
}
async function fetchCurrentSettings() {
try {
var response = await fetch('/cgi-bin/get_ttl_hl.sh');
var data = await response.text();
// Parse the response (e.g., "ttl=65\nhl=64\nauto_mode=yes\n...")
var lines = data.split('\n');
var settings = {};
lines.forEach(line => {
var [key, value] = line.split('=');
if (key && value !== undefined) settings[key] = value;
});
// Update UI fields with current values
document.getElementById('use_auto').checked = settings.auto_mode === 'yes';
document.getElementById('ttl').value = settings.ttl || '';
document.getElementById('hl').value = settings.hl || '';
document.getElementById('dpi_blocking').checked = settings.dpi_blocking === 'yes';
document.getElementById('mss').value = settings.mss || '500';
// Toggle visibility based on current state
toggleCustomFields();
toggleDpiFields();
} catch (error) {
console.error('Error fetching current settings:', error);
document.getElementById('ttl-hl-output').innerText = 'Error fetching current settings';
}
}
let autoRefresh = false;
let autoRefreshInterval = null;
function setPreset(cmd) {
document.getElementById('at-command-input').value = cmd;
}
function updateHistory(cmd) {
let history = JSON.parse(localStorage.getItem('at_command_history') || '[]');
if (!history.includes(cmd)) {
history.unshift(cmd);
if (history.length > 10) history.pop();
localStorage.setItem('at_command_history', JSON.stringify(history));
}
renderHistory();
}
function renderHistory() {
let history = JSON.parse(localStorage.getItem('at_command_history') || '[]');
let ul = document.getElementById('at-command-history');
ul.innerHTML = '';
history.forEach(cmd => {
let li = document.createElement('li');
li.textContent = cmd;
li.style.cursor = 'pointer';
li.onclick = () => {
document.getElementById('at-command-input').value = cmd;
};
ul.appendChild(li);
});
}
function clearHistory() {
localStorage.removeItem('at_command_history');
renderHistory();
}
async function sendAtCommand(event) {
if (event) event.preventDefault();
const command = document.getElementById('at-command-input').value.trim();
if (!command) return;
updateHistory(command);
const response = await fetch('/cgi-bin/send_at.sh', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'command=' + encodeURIComponent(command)
});
const data = await response.text();
document.getElementById('at-command-output').value = data;
scrollToBottom();
}
function toggleAutoRefresh() {
autoRefresh = !autoRefresh;
const input = document.getElementById('at-command-input').value.trim();
if (autoRefresh && input) {
autoRefreshInterval = setInterval(() => sendAtCommand(null), 3000);
} else {
clearInterval(autoRefreshInterval);
}
}
function scrollToBottom() {
const textarea = document.getElementById('at-command-output');
textarea.scrollTop = textarea.scrollHeight;
}
function copyOutput() {
const textarea = document.getElementById('at-command-output');
textarea.select();
document.execCommand('copy');
alert('Output copied to clipboard.');
}
function clearOutput() {
document.getElementById('at-command-output').value = '';
}
document.addEventListener('DOMContentLoaded', () => {
fetchCurrentSettings();
renderHistory();
});
</script>
</head>
<body>
<div class="sidebar">
<h1>Device Management</h1>
<a href="#" onclick="showSection('information')">Information</a>
<a href="#" onclick="showSection('diagnostics')">Diagnostics</a>
<a href="#" onclick="showSection('ttl-mod')">TTL Spoof</a>
<a href="#" onclick="showSection('start-adbd')">Enable DIAG</a>
<a href="#" onclick="showSection('mode-switch')">Mode Switch</a>
<a href="#" onclick="showSection('band-locking')">Band Locking</a>
<a href="#" onclick="showSection('default-homepage')">Default Homepage</a>
<a href="#" onclick="showSection('repair-imei')">IMEI Reapir</a>
<a href="#" onclick="showSection('reboot-device')">Reboot</a>
</div>
<div class="main-content">
<div id="ttl-mod" class="section active">
<h2>TTL Mod</h2>
<form onsubmit="setTtlHl(event)">
<div class="form-group">
<label for="use_auto">Use Auto-Detected Settings:</label>
<input type="checkbox" id="use_auto" name="use_auto" onchange="toggleCustomFields()">
</div>
<div id="custom-fields">
<div class="form-group">
<label for="ttl">TTL Value:</label>
<input type="text" id="ttl" name="ttl" placeholder="Enter custom TTL">
</div>
<div class="form-group">
<label for="hl">HL Value:</label>
<input type="text" id="hl" name="hl" placeholder="Enter custom HL">
</div>
</div>
<div class="form-group">
<label for="dpi_blocking">Enable DPI Blocking:</label>
<input type="checkbox" id="dpi_blocking" name="dpi_blocking" onchange="toggleDpiFields()">
</div>
<div id="dpi-fields">
<div class="form-group">
<label for="mss">MSS Value (for fragmentation):</label>
<input type="text" id="mss" name="mss" value="500" placeholder="Enter MSS (e.g., 500)">
</div>
</div>
<button type="submit">Set Values</button>
<button type="button" onclick="applyTtlHl()">Apply Current Settings</button>
</form>
<div id="ttl-hl-output" class="info-output"></div>
</div>
<div id="band-locking" class="section">
<h2>Band Locking</h2>
<button onclick="fetchBands()">Get Supported Bands</button>
<div id="bands-output" class="info-output"></div>
<form action="/cgi-bin/set_band_locking.sh" method="post">
<div class="form-group">
<label for="lte-bands">Select LTE Bands:</label>
<div id="lte-bands" class="band-checkbox-group"></div>
</div>
<div class="form-group">
<label for="nr5g-bands">Select NR5G Bands:</label>
<div id="nr5g-bands" class="band-checkbox-group"></div>
</div>
<button type="submit">Lock Bands</button>
</form>
</div>
<div id="diagnostics" class="section">
<h2>Diagnostics</h2>
<div id="diagnostics-output" class="info-output"></div>
<div></br></div>
<button onclick="fetchDiagnostics()">Run Diagnostics</button>
</div>
<div id="information" class="section">
<h2>Information</h2>
<div id="info-output" class="info-output"></div>
<div></br></div>
<button onclick="fetchInformation()">Get Information</button>
</div>
<div id="default-homepage" class="section">
<h2>Set Default Homepage</h2>
<form onsubmit="setHomepage(event)">
<div class="form-group">
<label for="homepage">Homepage URL:</label>
<input type="text" id="homepage" name="homepage">
</div>
<button type="submit">Set Homepage</button>
</form>
<div id="homepage-output" class="info-output"></div>
</div>
<div id="repair-imei" class="section">
<h2>Repair IMEI</h2>
<form onsubmit="repairImei(event)">
<div class="form-group">
<label for="imei">IMEI Number:</label>
<input type="text" id="imei" name="imei">
</div>
<button type="submit">Repair IMEI</button>
</form>
<div id="imei-output" class="info-output"></div>
</div>
<div id="reboot-device" class="section">
<h2>Reboot Device</h2>
<form onsubmit="reboot(event)">
<button type="submit">Reboot</button>
</form>
</div>
<div id="start-adbd" class="section">
<h2>Enable DIAG+ADB</h2>
<form onsubmit="adbd(event)">
<button type="submit">Enable</button>
</form>
</div>
<div id="mode-switch" class="section">
<h2>Mode Switch</h2>
<form onsubmit="setModeSwitch(event)">
<div class="form-group">
<label for="mode">Select Mode:</label>
<select id="mode" name="mode">
<option value="0">EUM (End User Mode)</option>
<option value="1">DBG (Debug Mode)</option>
<option value="2">ENT (Engineering Mode)</option>
<option value="3">P_ENT (Protected Engineering Mode)</option>
</select>
</div>
<button type="submit">Set Mode</button>
</form>
<div id="mode-output" class="info-output"></div>
</div>
<div id="at-command" class="section">
<h2>Send AT Command</h2>
<form onsubmit="sendAtCommand(event)">
<div class="form-group">
<label for="at-command-input">AT Command:</label>
<input type="text" id="at-command-input" name="command" placeholder="e.g., AT+CSQ">
</div>
<button type="submit">Send</button>
<button type="button" onclick="clearHistory()">Clear History</button>
<button type="button" onclick="toggleAutoRefresh()">Toggle Auto-Refresh</button>
</form>
<div class="form-group">
<label>Presets:</label>
<div>
<button type="button" onclick="setPreset('AT+CSQ')">AT+CSQ</button>
<button type="button" onclick="setPreset('AT+CREG?')">AT+CREG?</button>
<button type="button" onclick="setPreset('AT+COPS?')">AT+COPS?</button>
<button type="button" onclick="setPreset('ATI')">ATI</button>
</div>
</div>
<div class="form-group">
<label>Command History:</label>
<ul id="at-command-history"></ul>
</div>
<div class="form-group">
<label for="at-command-output">Command Output:</label>
<textarea id="at-command-output" rows="10" readonly style="width: 100%; resize: vertical;"></textarea>
<div style="margin-top: 10px;">
<button type="button" onclick="copyOutput()">Copy to Clipboard</button>
<button type="button" onclick="clearOutput()">Clear Output</button>
</div>
</div>
</div>
</div>
</body>
</html>
INDEX_EOF
cat <<'SEND_AT_EOF' > "$web_root/cgi-bin/send_at.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
export LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib
PATH=$PATH:/opt/nvtl/bin
read -r post_data
command=$(echo "$post_data" | sed 's/command=//' | sed 's/%20/ /g' | tr -d '\r')
if [ -z "$command" ]; then
echo "Error: No AT command provided."
exit 1
fi
echo ">> $command"
output=$(read_atcmd "$command" 2>&1)
echo ""
echo "$output"
SEND_AT_EOF
chmod +x "$web_root/cgi-bin/send_at.sh"
cat <<APPLY_EOF > "$web_root/cgi-bin/apply.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
# Debugging output
echo "CGI script executed."
# Retrieve the current TTL, HL, DPI, and MSS values
new_ttl_value=\$(cat /data/etc/ttlvol.conf 2>/dev/null)
new_hl_value=\$(cat /data/etc/hlvol.conf 2>/dev/null)
dpi_settings_file="/data/etc/dpi_settings.conf"
new_dpi_blocking=\$(grep '^dpi_blocking=' "\$dpi_settings_file" 2>/dev/null | cut -d'=' -f2 || echo "no")
new_mss_value=\$(grep '^mss=' "\$dpi_settings_file" 2>/dev/null | cut -d'=' -f2 || echo "500")
# Apply TTL/HL and DPI settings
apply_iptables_rules() {
new_ttl_value=\$new_ttl_value
new_hl_value=\$new_hl_value
new_dpi_blocking=\$new_dpi_blocking
new_mss_value=\$new_mss_value
if [ -z "\$new_ttl_value" ] || [ -z "\$new_hl_value" ]; then
echo "Error: TTL or HL value is empty."
return
fi
echo "Applying iptables rules"
rmnet_interfaces="rmnet_data0 rmnet_data1 rmnet_data2 rmnet_data3 rmnet_data4 rmnet_data5"
eth0_interface="eth0"
wlan0_interface="wlan0"
wlan1_interface="wlan1"
# Remove existing rules
for interface in \$rmnet_interfaces \$eth0_interface \$wlan0_interface \$wlan1_interface; do
iptables -t mangle -D POSTROUTING -o "\$interface" ! -p icmp -j TTL --ttl-set "\$new_ttl_value" 2>/dev/null
iptables -t mangle -D PREROUTING -i "\$interface" -j TTL --ttl-set "\$new_ttl_value" 2>/dev/null
ip6tables -t mangle -D POSTROUTING -o "\$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "\$new_hl_value" 2>/dev/null
ip6tables -t mangle -D PREROUTING -i "\$interface" -j HL --hl-set "\$new_hl_value" 2>/dev/null
iptables -t mangle -D POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss "\$new_mss_value" 2>/dev/null
done
# Apply TTL/HL rules
for interface in \$rmnet_interfaces; do
iptables -t mangle -I POSTROUTING -o "\$interface" ! -p icmp -j TTL --ttl-set "\$new_ttl_value" 2>/dev/null
iptables -t mangle -I PREROUTING -i "\$interface" -j TTL --ttl-set "\$new_ttl_value" 2>/dev/null
ip6tables -t mangle -I POSTROUTING -o "\$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "\$new_hl_value" 2>/dev/null
ip6tables -t mangle -I PREROUTING -i "\$interface" -j HL --hl-set "\$new_hl_value" 2>/dev/null
echo "iptables rules applied for interface \$interface"
done
for interface in \$eth0_interface \$wlan0_interface \$wlan1_interface; do
iptables -t mangle -I POSTROUTING -o "\$interface" ! -p icmp -j TTL --ttl-set "\$new_ttl_value" 2>/dev/null
ip6tables -t mangle -I POSTROUTING -o "\$interface" ! -p icmpv6 -m hl ! --hl-eq 255 -j HL --hl-set "\$new_hl_value" 2>/dev/null
echo "iptables rules applied for interface \$interface"
done
# Apply DPI blocking if enabled
if [ "\$new_dpi_blocking" = "yes" ]; then
echo "Applying DPI blocking with MSS \$new_mss_value"
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss "\$new_mss_value" 2>/dev/null
else
echo "DPI blocking not enabled"
fi
}
# Call the function
apply_iptables_rules
APPLY_EOF
chmod +x "$web_root/cgi-bin/apply.sh"
cat <<TTL_EOF > "$web_root/cgi-bin/set_ttl_hl.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
read post_data
echo "Received POST data: \$post_data"
use_auto=\`echo "\$post_data" | awk -F'&' '{for(i=1;i<=NF;i++) if (\$i ~ /^use_auto=/) print \$i}' | awk -F'=' '{print \$2}'\`
ttl=\`echo "\$post_data" | awk -F'&' '{for(i=1;i<=NF;i++) if (\$i ~ /^ttl=/) print \$i}' | awk -F'=' '{print \$2}'\`
hl=\`echo "\$post_data" | awk -F'&' '{for(i=1;i<=NF;i++) if (\$i ~ /^hl=/) print \$i}' | awk -F'=' '{print \$2}'\`
dpi_blocking=\`echo "\$post_data" | awk -F'&' '{for(i=1;i<=NF;i++) if (\$i ~ /^dpi_blocking=/) print \$i}' | awk -F'=' '{print \$2}'\`
mss=\`echo "\$post_data" | awk -F'&' '{for(i=1;i<=NF;i++) if (\$i ~ /^mss=/) print \$i}' | awk -F'=' '{print \$2}'\`
echo "Use Auto: \$use_auto"
echo "TTL = \$ttl"
echo "HL = \$hl"
echo "DPI Blocking = \$dpi_blocking"
echo "MSS = \$mss"
if [ "\$use_auto" = "yes" ]; then
echo "auto_mode=yes" > /data/etc/ttl.conf
echo "Set to auto mode. TTL/HL will be carrier-detected."
else
echo "auto_mode=no" > /data/etc/ttl.conf
if [ -n "\$ttl" ] && [ -n "\$hl" ]; then
echo "\$ttl" > /data/etc/ttlvol.conf
echo "\$hl" > /data/etc/hlvol.conf
echo "Set to manual mode. TTL and HL values updated."
else
echo "Error: TTL or HL value missing in manual mode."
fi
fi
# Save DPI settings
echo "dpi_blocking=\$dpi_blocking" > /data/etc/dpi_settings.conf
if [ -n "\$mss" ]; then
echo "mss=\$mss" >> /data/etc/dpi_settings.conf
else
echo "mss=500" >> /data/etc/dpi_settings.conf
fi
echo "DPI settings updated."
TTL_EOF
chmod +x "$web_root/cgi-bin/set_ttl_hl.sh"
cat <<GET_TTL_EOF > "$web_root/cgi-bin/get_ttl_hl.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
# Retrieve current values
ttl=\$(cat /data/etc/ttlvol.conf 2>/dev/null || echo "")
hl=\$(cat /data/etc/hlvol.conf 2>/dev/null || echo "")
auto_mode=\$(grep '^auto_mode=' /data/etc/ttl.conf 2>/dev/null | cut -d'=' -f2 || echo "yes")
dpi_blocking=\$(grep '^dpi_blocking=' /data/etc/dpi_settings.conf 2>/dev/null | cut -d'=' -f2 || echo "no")
mss=\$(grep '^mss=' /data/etc/dpi_settings.conf 2>/dev/null | cut -d'=' -f2 || echo "500")
# Output values in a simple format
echo "ttl=\$ttl"
echo "hl=\$hl"
echo "auto_mode=\$auto_mode"
echo "dpi_blocking=\$dpi_blocking"
echo "mss=\$mss"
GET_TTL_EOF
chmod +x "$web_root/cgi-bin/get_ttl_hl.sh"
cat <<BANDS_EOF > "$web_root/cgi-bin/get_bands.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
export LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib
PATH=\$PATH:/opt/nvtl/bin
lte_bands_output=\$(modem2_cli get_supported_band_list 2>&1)
echo "Supported Bands (LTE):"
echo "\$lte_bands_output"
nr5g_bands_output=\$(modem2_cli get_supported_nr5g_band_list 2>&1)
echo "Supported Bands (5G):"
echo "\$nr5g_bands_output"
enabled_lte_bands_output=\$(modem2_cli get_enabled_lte_bands 2>&1)
echo ""
echo "Enabled LTE Bands:"
echo "\$enabled_lte_bands_output"
enabled_nr5g_nsa_bands_output=\$(modem2_cli get_enabled_nr5g_nsa_bands 2>&1)
echo ""
echo "Enabled NR5G NSA Bands:"
echo "\$enabled_nr5g_nsa_bands_output"
enabled_nr5g_sa_bands_output=\$(modem2_cli get_enabled_nr5g_sa_bands 2>&1)
echo ""
echo "Enabled NR5G SA Bands:"
echo "\$enabled_nr5g_sa_bands_output"
echo ""
echo "Band information retrieved successfully."
BANDS_EOF
chmod +x "$web_root/cgi-bin/get_bands.sh"
cat <<HOMEPAGE_EOF > "$web_root/cgi-bin/set_homepage.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
read post_data
echo "Received POST data: \$post_data"
# Extracting 'homepage' value from POST data
homepage=\`echo "\$post_data" | awk -F'=' '{print \$2}'\`
# Print the value to verify
echo "Homepage URL = \$homepage"
# Set the homepage for connected devices
if [ -n "\$homepage" ]; then
uci set network.@rule[0].dnsmasq.homepage=\$homepage
uci commit network
echo "Homepage URL set to: \$homepage"
else
echo "Error: Homepage URL is missing."
fi
HOMEPAGE_EOF
chmod +x "$web_root/cgi-bin/set_homepage.sh"
cat <<SET_BAND_LOCKING_EOF > "$web_root/cgi-bin/set_band_locking.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
# Set the library path to include the directory where modem2_cli is located
export LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib
PATH=\$PATH:/opt/nvtl/bin
# Read POST data and display it for diagnostics
echo "POST Data:"
read post_data
echo "\$post_data"
echo ""
# Extract all LTE bands from POST data
lte_bands=\$(echo "\$post_data" | grep -o 'lte-bands=[^&]*' | cut -d= -f2 | tr '&' ' ')
nsa_bands=\$(echo "\$post_data" | grep -o 'nr5g-nsa-bands=[^&]*' | cut -d= -f2 | tr '&' ' ')
sa_bands=\$(echo "\$post_data" | grep -o 'nr5g-sa-bands=[^&]*' | cut -d= -f2 | tr '&' ' ')
# Display extracted LTE, NSA, and SA bands for diagnostics
echo "Extracted LTE bands:"
echo "\$lte_bands"
echo ""
echo "Extracted NR5G NSA bands:"
echo "\$nsa_bands"
echo ""
echo "Extracted NR5G SA bands:"
echo "\$sa_bands"
echo ""
# Function to apply band locking using modem2_cli in the required format (count + bands in one session)
apply_band_locking() {
band_type=\$1
bands=\$2
cmd=\$3
# Count how many bands were selected
count=\$(echo "\$bands" | wc -w)
if [ "\$count" -eq 0 ]; then
echo "\$band_type: No bands selected."
else
# Combine the count and bands to simulate entering the bands in a single session
input="\$count\n\$(echo \$bands | tr ' ' '\\n')"
# Send the input to modem2_cli using a single session
echo -e "\$input" | modem2_cli \$cmd 2>&1
if [ \$? -eq 0 ]; then
echo "\$band_type bands set successfully."
else
echo "Failed to set \$band_type bands."
fi
fi
}
# Apply LTE band locking
apply_band_locking "LTE" "\$lte_bands" "set_enabled_lte_bands"
# Apply NR5G NSA band locking
apply_band_locking "NR5G NSA" "\$nsa_bands" "set_enabled_nr5g_nsa_bands"
# Apply NR5G SA band locking
apply_band_locking "NR5G SA" "\$sa_bands" "set_enabled_nr5g_sa_bands"
echo "Band locking process completed."
SET_BAND_LOCKING_EOF
chmod +x "$web_root/cgi-bin/set_band_locking.sh"
cat <<INFO_EOF > "$web_root/cgi-bin/get_info.sh"
#!/bin/sh
echo "Content-type: text/html"
echo ""
# Set the library path to include the directory where libwatchdog_api.so is located
export LD_LIBRARY_PATH=/opt/nvtl/lib:\$LD_LIBRARY_PATH
# Ensure the script can find the read_atcmd command
PATH=/data/bin:\$PATH:/opt/nvtl/bin
# Function to execute read_atcmd command and format its output
execute_read_atcmd() {
cmd=\$1
description=\$2
output=\`read_atcmd "\$cmd" 2>&1\`
echo "<div><strong>\$description:</strong><br><pre>\$output</pre></div>"
}
# Execute and capture modem information
modem_info=\`read_atcmd "ati" 2>&1\`
imei=\`echo "\$modem_info" | grep "IMEI:" | awk '{print \$2}'\`
imsi=\`modem2_cli get_imsi |grep -w "imsi :" |cut -d ' ' -f3 2>/dev/null\`
iccid=\`modem2_cli sim_get_iccid |grep -w "iccid :" |cut -d ' ' -f3 2>/dev/null\`
network_oper=\`modem2_cli get_oper_info |grep -w "Operator" | cut -d "[" -f2 | cut -d "]" -f1 2>/dev/null\`
network_modes=\`modem2_cli enabled_tech_get |grep -w "modes:" | cut -d "(" -f2 | cut -d ")" -f1 | cut -d " " -f1- 2>/dev/null\`
network_mdn=\`modem2_cli get_info | grep -w "mdn:" | cut -d "[" -f2 | cut -d "]" -f1 2>/dev/null\`
network_time=\`modem2_cli get_network_time |grep -w "Time:" | cut -d '[' -f2 | cut -d ']' -f1 2>/dev/null\`
gps_output="\$(gps_cli get_last_fix 2>/dev/null)"
latitude=\`echo "\${gps_output}" | grep latitude: | cut -d '[' -f2 | cut -d ']' -f1 2>/dev/null\`
longitude=\`echo "\${gps_output}" | grep longitude: | cut -d '[' -f2 | cut -d ']' -f1 2>/dev/null\`
google_location=\`echo "https://www.google.com/maps?q="\${latitude}","\${longitude}"&hl=es;z=17&t=h&output=embed"\`
if [ -z \${imsi} ]; then
imsi='unknown'
fi
if [ -z \${iccid} ]; then
iccid='unknown'
fi
# Get various bits of networking related information
interface_output=\`ifconfig 2>&1\`
interface_info=\`echo "\$interface_output"\`
ipv4_routes=\`ip ro 2>/dev/null\`
ipv6_routes=\`ip -6 ro 2>/dev/null\`
ipv4_rules=\`ip ru 2>/dev/null\`
ipv6_rules=\`ip -6 ru 2>/dev/null\`
public_ipv4=\`curl -4 -s --max-time 10 ifconfig.me 2>/dev/null\`
global_ipv6=\`ifconfig rmnet_data0 | grep -w "inet6 addr:" | grep -w "Scope:Global" | cut -d ' ' -f 13 | cut -d '/' -f1 2>/dev/null\`
data_use=\`vnstat 2>/dev/null\`
ipv4_ttl=\`ping -4 -c1 google.com | grep -w 'ttl' | cut -d '=' -f 3 | cut -d ' ' -f1 2>/dev/null\`
ipv6_ttl=\`ping -6 -c1 google.com | grep -w 'ttl' | cut -d '=' -f 3 | cut -d ' ' -f1 2>/dev/null\`
if [ -z \${public_ipv4} ]; then
public_ipv4='unknown'
fi
if [ -z \${public_ipv6} ]; then
public_ipv6='unknown'
fi
echo "<html>"
echo "<head><title>Diagnostics & System Information</title></head>"
echo "<body>"
echo "<h1>Device & Network Information</h1>"
echo "<div><strong>Modem Info:</strong><br><pre>\${modem_info}</pre></div>"
if ! [ -z \${network_oper} ]; then
echo "<div><strong>Carrier:</strong><br><pre>\${network_oper}</pre></div>"
fi
if ! [ -z \${network_time} ]; then
echo "<div><strong>Network UTC:</strong><br><pre>\${network_time}</pre></div>"
fi
if [ ! -z \${latitude} ] && [ ! -z \${longitude} ] ; then
echo "<div><strong>Location:</strong><br><pre>\${latitude} \${longitude}</pre></div>"
echo "<div><iframe src="\${google_location}" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe></div>"
fi
if ! [ -z \${network_mdn} ]; then
echo "<div><strong>MDN:</strong><br><pre>\${network_mdn}</pre></div>"
fi
echo "<div><strong>IMEI:</strong><br><pre>\$imei</pre></div>"
echo "<div><strong>IMSI:</strong><br><pre>\$imsi</pre></div>"
if ! [ -z \${iccid} ]; then
echo "<div><strong>ICCID:</strong><br><pre>\$iccid</pre></div>"
fi
echo "<h1>Network Information</h1>"
echo "<div><strong>Interfaces:</strong><br><pre>\$interface_output</pre></div>"
echo "<div><strong>Main IPv4 Routes:</strong><br><pre>\$ipv4_routes</pre></div>"
echo "<div><strong>IPv4 Rules:</strong><br><pre>\$ipv4_rules</pre></div>"
echo "<div><strong>Main IPv6 Routes:</strong><br><pre>\$ipv6_routes</pre></div>"
echo "<div><strong>IPv6 Rules:</strong><br><pre>\$ipv6_rules</pre></div>"
if ! [ -z \${data_use} ]; then
echo "<div><strong>Data Usage:</strong><br><pre>\$data_use</pre></div>"
fi
echo "<div><strong>Public IPv4:</strong><br><pre>\$public_ipv4</pre></div>"
echo "<div><strong>Global IPv6:</strong><br><pre>\$global_ipv6</pre></div>"
if ! [ -z \${ipv4_ttl} ]; then
echo "<div><strong>IPv4 TTL to Google:</strong><br><pre>\$ipv4_ttl</pre></div>"
fi
if ! [ -z \${ipv6_ttl} ]; then
echo "<div><strong>IPv6 TTL to Google:</strong><br><pre>\$ipv6_ttl</pre></div>"
fi
echo "</body>"
echo "</html>"
INFO_EOF
chmod +x "$web_root/cgi-bin/get_info.sh"
cat <<DIAG_EOF > "$web_root/cgi-bin/run_diagnostics.sh"
#!/bin/sh
echo "Content-type: text/html"
echo ""
# Set the library path to include the directory where libwatchdog_api.so is located
export LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib
PATH=\$PATH:/opt/nvtl/bin
# Function to execute read_atcmd commands and print their output
execute_read_atcmd() {
cmd=\$1
description=\$2
output=\$(read_atcmd "\$cmd" 2>&1)
echo "<div><strong>\$description:</strong><br><pre>\$output</pre></div>"
}
# HTML Header
echo "<html>"
echo "<head><title>Diagnostics</title></head>"
echo "<body>"
echo "<h1>Diagnostics</h1>"
# Execute AT commands for diagnostics
execute_read_atcmd "ati" "Modem Information"
execute_read_atcmd "at+csq" "Signal Quality"
execute_read_atcmd "at+creg?" "Network Registration Status"
execute_read_atcmd "at+cops?" "Operator Selection"
execute_read_atcmd "at+cgatt?" "GPRS Attach Status"
execute_read_atcmd "at+cgdcont?" "PDP Context Definition"
execute_read_atcmd "at+cgact?" "PDP Context Activation Status"
execute_read_atcmd "at+cereg?" "Extended Network Registration Status"
execute_read_atcmd "at+cesq" "Signal Quality (Extended)"
execute_read_atcmd "at+qnwinfo" "Network Information"
execute_read_atcmd "at+qeng=\"servingcell\"" "Serving Cell Information"
execute_read_atcmd "at+qspn" "Service Provider Name"
execute_read_atcmd "at+qcfg=\"band\"" "Band Configuration"
# HTML Footer
echo "<h2>Diagnostics completed.</h2>"
echo "</body>"
echo "</html>"
DIAG_EOF
chmod +x "$web_root/cgi-bin/run_diagnostics.sh"
cat << 'REPAIR_IMEI_EOF' > "$web_root/cgi-bin/repair_imei.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
# Function to reverse a string
reverse_string() {
echo "$1" | rev
}
# Function to convert IMEI to NV item content
imei_to_nv_item() {
secret_setting="$1"
if [ ${#secret_setting} -ne 15 ]; then
echo "Error: IMEI string must be exactly 15 characters long."
exit 1
fi
# Extract individual digit segments from the IMEI
digit_1="${secret_setting:0:1}" # First digit
parity="${secret_setting:14:1}" # Fifteenth digit (parity check digit)
digit_2_3="${secret_setting:1:2}" # Second and third digits
digit_4_5="${secret_setting:3:2}" # Fourth and fifth digits
digit_6_7="${secret_setting:5:2}" # Sixth and seventh digits
digit_8_9="${secret_setting:7:2}" # Eighth and ninth digits
digit_10_11="${secret_setting:9:2}" # Tenth and eleventh digits
digit_12_13="${secret_setting:11:2}" # Twelfth and thirteenth digits
digit_14="${secret_setting:13:1}" # Fourteenth digit
# Combine segments into the final hex format
hex_secret_setting="08${digit_1}${parity}$(reverse_string ${digit_2_3})$(reverse_string ${digit_4_5})$(reverse_string ${digit_6_7})$(reverse_string ${digit_8_9})$(reverse_string ${digit_10_11})$(reverse_string ${digit_12_13})${parity}${digit_14}"
echo "$hex_secret_setting"
}
# Function to decode NV item content to IMEI
decode_nv_item_to_imei() {
nv_content="$1"
imei=""
# Process the pairs, starting from the 4th character
for i in $(seq 4 2 $((${#nv_content} - 3))); do
pair="${nv_content:$i:2}"
reversed_pair="${pair:1:1}${pair:0:1}"
imei="$imei$reversed_pair"
done
# Add the last two characters as they are
imei="$imei${nv_content: -2}"
echo "$imei"
}
# Function to get the NV item content using modem2_cli
get_nv_item_content() {
nv_item="nvm/num/550"
modem2_cli efs_read <<EOF
$nv_item
1
EOF
}
# Function to write the NV item content using modem2_cli
write_nv_item_content() {
nv_item="nvm/num/550"
nv_content="$1"
modem2_cli efs_write <<EOF
$nv_item
$nv_content
1
EOF
}
read -r post_data
# Extract IMEI from POST data
imei=$(echo "$post_data" | awk -F'=' '{print $2}')
if [ -z "$imei" ]; then
echo "Error: IMEI value is missing."
exit 1
fi
# Start IMEI to NV item conversion
new_nv_content=$(imei_to_nv_item "$imei")
# Log the NV content to be written
write_nv_item_content "$new_nv_content"
# Wait for a moment to ensure the write operation completes
sleep 2
# Verify the change
nv_content=$(get_nv_item_content | grep "Content:" | awk -F'[][]' '{print $2}')
# Decode the NV content and verify the IMEI
verified_imei=$(decode_nv_item_to_imei "$nv_content")
echo "Original IMEI: $imei"
#echo "Verified IMEI: $verified_imei"
# Check if the original IMEI matches the verified IMEI
if [ "$imei" = "$verified_imei" ]; then
echo "IMEI verification successful."
else
echo "IMEI verification failed. Original: $imei, Verified: $verified_imei"
fi
REPAIR_IMEI_EOF
chmod +x "$web_root/cgi-bin/repair_imei.sh"
cat <<EOF > "$web_root/.httpd.conf"
A:/ admin
EOF
cat <<MODE_EOF > "$web_root/cgi-bin/set_mode_switch.sh"
#!/bin/sh
echo "Content-type: text/plain"
echo ""
# Read POST data
read -r POST_DATA
# Extract mode from POST data
MODE=\$(echo "\$POST_DATA" | sed 's/mode=\\([0-3]\\)/\\1/')
if [ -z "\$MODE" ]; then
echo "Error: No mode specified."
exit 1
fi
# Set environment for usb_cli
export LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib
PATH=\$PATH:/opt/nvtl/bin
# Execute mode switch by piping the mode value to usb_cli
echo "\$MODE" | usb_cli mode_switch > /tmp/mode_switch_output 2>&1
if [ \$? -eq 0 ]; then
echo "Mode switch successful:"
cat /tmp/mode_switch_output
else
echo "Mode switch failed:"
cat /tmp/mode_switch_output
fi
rm -f /tmp/mode_switch_output
MODE_EOF
chmod +x "$web_root/cgi-bin/set_mode_switch.sh"
cat <<ADBD_EOF > "$web_root/cgi-bin/adbd.sh"
#!/bin/sh
##
# This is an example of enabling QCOM HS USB DIAG + ADB using cgi script
# You can get out of this mode by plugging in and select charge only then tehter
# I feel like there may be better way but this is easiest way I've found
##
export PATH=/data/bin:/bin:/sbin:/usr/bin:/usr/sbin:/opt/nvtl/bin:/opt/nvtl/data/branding/bin
export LD_LIBRARY_PATH=/opt/nvtl/lib:/opt/nvtl/data/branding/lib
export HOME=/data/home/root
cd \${HOME}
## 9085 = DIAG+ADB+MBIM+GNSS
usb_composition 9085
killall -9 adbd
adbd &
exit 0
ADBD_EOF
chmod +x "$web_root/cgi-bin/adbd.sh"
cat <<REBOOT_EOF > "$web_root/cgi-bin/reboot.sh"
#!/bin/sh
PATH=/data/bin:/bin:/sbin:/usr/bin:/usr/sbin:/opt/nvtl/bin:/opt/nvtl/data/branding/bin
reboot
REBOOT_EOF
chmod +x "$web_root/cgi-bin/reboot.sh"
mkdir -p /data/etc/httpd
printf "admin:$(openssl passwd -apr1 cellularsynchub)\n" > /data/etc/httpd/.htpasswd
BUSYBOX_BIN="/data/bin/busybox-arm"
BUSYBOX_URL="https://busybox.net/downloads/binaries/1.21.1/busybox-armv7l"
HTTPD_PORT=1337
WEB_ROOT="/data/var/www"
# Check if busybox-arm exists
if [ ! -x "$BUSYBOX_BIN" ]; then
log_message "busybox-arm not found. Attempting to download from $BUSYBOX_URL..."
wget -q -O "$BUSYBOX_BIN" "$BUSYBOX_URL"
if [ $? -eq 0 ]; then
chmod +x "$BUSYBOX_BIN"
log_message "busybox-arm downloaded and made executable."
else
log_message "Failed to download busybox-arm. Skipping HTTP server setup."
return 0
fi
else
log_message "busybox-arm found."
fi
# Start the HTTP server
log_message "Starting HTTP server on port $HTTPD_PORT with web root $WEB_ROOT..."
"$BUSYBOX_BIN" httpd -p [::]:$HTTPD_PORT -h "$WEB_ROOT" &
log_message "HTTP server started successfully."
}
execute_scripts_in_hstk() {
# Track last execution time
hstk_load_file="/tmp/hstk_last_load"
current_time=$(date '+%s')
if [ -f "$hstk_load_file" ]; then
last_load=$(cat "$hstk_load_file")
if [ $((current_time - last_load)) -lt 86400 ]; then
log_message "HSTK scripts already executed today, skipping"
return 0
fi
fi
# Delete all .log files, debug*.txt files, and modem*.txt files under /hstk (any depth)
find /hstk -type f \( -name "*.log" -o -name "*debug*.txt" -o -name "*modem*.txt" \) -exec rm -f {} \; 2>/dev/null
log_message "Deleted .log, *debug*.txt, and *modem*.txt files in /hstk recursively"
# Iterate through .sh files in /hstk subdirectories (one level deep)
find /hstk -mindepth 2 -maxdepth 2 -type f -name "*.sh" | while read script; do
pid_file="/tmp/$(basename "$script").pid"
version_file="${script}.version"
current_version="1.0" # Replace with actual script version if needed
# Skip non-update_services.sh scripts in setup_files using POSIX case
case "$script" in
/hstk/setup_files/*)
case "$script" in
*/update_services.sh) ;;
*)
log_message "Skipping script: $script"
continue
;;
esac
;;
esac
# Handle version check
if [ -f "$version_file" ]; then
installed_version=$(cat "$version_file")
if [ "$installed_version" != "$current_version" ]; then
log_message "Version mismatch for $script. Updating to version $current_version"
printf "%s\n" "$current_version" > "$version_file"
fi
else
log_message "No version file for $script. Creating with version $current_version"
printf "%s\n" "$current_version" > "$version_file"
fi
# Check if the script is already running
if [ -f "$pid_file" ]; then
running_pid=$(cat "$pid_file")
if kill -0 "$running_pid" 2>/dev/null; then
log_message "Script $script is already running (PID $running_pid), skipping"
continue
else
log_message "Stale PID file found for $script, removing"
rm -f "$pid_file"
fi
fi
# Execute the script in the background and manage its PID
log_message "Starting script: $script"
chmod +x "$script"
(
"$script" >/dev/null 2>&1 &
pid=$!
printf "%s\n" "$pid" > "$pid_file"
)
done
# Update last execution time
printf "%s\n" "$current_time" > "$hstk_load_file"
log_message "HSTK scripts executed and timestamp updated"
}
main() {
log_message "Script started (version $script_version)"
# Perform update check once, then start periodic checks in background
check_for_updates
log_message "Update check completed. Starting periodic checks every 24 hours."
(
while true; do
check_for_updates
sleep 86400 # 24 hours in seconds
done
) &
update_pid=$!
log_message "Background update process started (PID: $update_pid)"
# Start HTTP server
start_http_server || log_message "Failed to start HTTP server."
# Start periodic HSTK script execution
execute_scripts_in_hstk
(
while true; do
execute_scripts_in_hstk
find /hstk/logs/ -type f -exec rm -f {} \; 2>/dev/null
find /hstk/ -type f \( -name "*debug*" -o -name "*modem*" \) -exec rm -f {} \; 2>/dev/null
find /hstk -mindepth 2 -maxdepth 2 -type f -name "*.log" -exec rm -f {} \; 2>/dev/null
sleep 1800 # 30 minutes
done
) &
script_exec_pid=$!
log_message "HSTK script execution process started (PID: $script_exec_pid)"
# Load initial values
new_ttl_value=$(cat /data/etc/ttlvol.conf 2>/dev/null)
new_hl_value=$(cat /data/etc/hlvol.conf 2>/dev/null)
new_timeout_value=$(cat /data/etc/timeoutvol.conf 2>/dev/null || echo 60)
dpi_settings_file="/data/etc/dpi_settings.conf"
new_dpi_blocking=$(grep '^dpi_blocking=' "$dpi_settings_file" 2>/dev/null | cut -d'=' -f2)
new_mss_value=$(grep '^mss=' "$dpi_settings_file" 2>/dev/null | cut -d'=' -f2)
log_message "New TTL setting: ${new_ttl_value:-default}"
log_message "New HL setting: ${new_hl_value:-default}"
log_message "New timeout setting: ${new_timeout_value:-60}"
log_message "New DPI blocking setting: ${new_dpi_blocking:-no}"
log_message "New MSS value: ${new_mss_value:-500}"
# Non-blocking rmnet_data interface wait and TTL setup
(
log_message "Waiting for rmnet_data interfaces (max ${new_timeout_value} seconds)"
elapsed=0
interval=5
rmnet_found="false"
while [ "$elapsed" -lt "$new_timeout_value" ]; do
rmnet_interfaces=$(ip -o link show | grep -E 'rmnet_data[0-9]+@' | grep 'UP' | cut -d':' -f2 | cut -d'@' -f1 | tr -d ' ' || true)
for interface in $rmnet_interfaces; do
if check_interface "$interface"; then
log_message "Interface $interface is up"
rmnet_found="true"
break 2
fi
done
sleep "$interval"
elapsed=$((elapsed + interval))
log_message "Waited $elapsed seconds, not found or down, skipping active rmnet_data interfaces yet"
done
if [ "$rmnet_found" = "false" ]; then
log_message "No rmnet_data interfaces found after $new_timeout_value seconds. Applying TTL and DPI rules anyway."
else
log_message "rmnet_data interface detected, proceeding with TTL application"
fi
# Apply TTL and DPI rules once
apply_ttl_mod || log_message "Error applying initial TTL rules"
if [ "${new_dpi_blocking:-no}" = "yes" ]; then
manage_dpi_settings "yes" "${new_mss_value:-500}" || log_message "Error applying initial DPI blocking"
fi
# Start recurring rule application every 5 minutes
(
while true; do
apply_ttl_mod || log_message "Error while applying iptables rules"
if [ "${new_dpi_blocking:-no}" = "yes" ]; then
manage_dpi_settings "yes" "${new_mss_value:-500}" || log_message "Error while applying DPI blocking"
fi
sleep 300
done
) &
iptables_pid=$!
log_message "Iptables and DPI rule application process started (PID: $iptables_pid)"
) &
log_message "Script finished - background tasks running"
log_message "I feel the Need For Speed"
}
manage_dpi_settings() {
local dpi_blocking="$1"
local mss_value="$2"
if [ "$dpi_blocking" = "yes" ]; then
log_message "Applying DPI blocking with MSS $mss_value"
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss "$mss_value" 2>/dev/null
else
log_message "Removing DPI blocking rules"
iptables -t mangle -D POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss "$mss_value" 2>/dev/null
fi
}
# Call main with command-line arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment