How SmsForwarder Implements SMS Command Control with the smsf# Prefix
SmsForwarder listens for incoming SMS messages prefixed with smsf#, validates the sender against a safe-phone list, parses the remaining text into function-action-parameter triples, and dispatches commands to control Wi-Fi, FRPC tunnels, system power, or relay outbound SMS.
The SmsForwarder app (pppscn/SmsForwarder) provides a lightweight remote-control interface that allows users to trigger actions on an Android device via specially formatted text messages. By implementing SMS command control with the smsf# prefix, the app transforms incoming texts into executable commands without requiring internet connectivity.
Receiving and Validating SMS Commands
The entry point for all remote commands is the SmsReceiver broadcast receiver located in app/src/main/kotlin/cn/ppps/forwarder/receiver/SmsReceiver.kt. When the device receives an SMS, the receiver first checks whether the command feature is enabled via SettingUtils.enableSmsCommand and then inspects the message body for the mandatory smsf# prefix.
if (SettingUtils.enableSmsCommand && msg.startsWith("smsf#")) { … }
(see line 66 of SmsReceiver.kt)
Before processing, the receiver validates the sender's phone number against a user-defined safe-phone list stored in the app settings. Only messages from explicitly allowed numbers are accepted, preventing unauthorized remote access.
Parsing the smsf# Syntax
Once validated, the prefix is stripped and the remainder is passed to SmsCommandUtils.execute() (lines 44-45 of SmsReceiver.kt). The core parsing logic resides in app/src/main/kotlin/cn/ppps/forwarder/utils/SmsCommandUtils.kt, where the command string is split into a maximum of three segments using the # delimiter.
val cmdList = smsCommand.split("#", limit = 3)
val function = cmdList[0] // e.g., "wifi", "frpc", "system"
val action = cmdList[1] // e.g., "on", "start", "reboot"
val param = if (cmdList.count() > 2) cmdList[2] else ""
(see lines 37-44 of SmsCommandUtils.kt)
This structure creates a consistent grammar: smsf#<function>#<action>#<optional_parameter>.
Command Dispatch and Implementation
A Kotlin when statement routes the parsed request to the appropriate handler. The following subsections detail the implementation for each supported command category.
FRPC Tunnel Control
The frpc command manages Frp (Fast Reverse Proxy) tunnels via the native Frpclib library. When the function is frpc, the action (start or stop) and optional UID parameter determine which tunnels to control.
// Start all autorun configs or a specific UID
Frpclib.runContent(config.uid, config.file)
// Stop specific tunnel
Frpclib.close(uid)
(see lines 45-78 of SmsCommandUtils.kt)
HTTP Server Management
The httpserver command controls the built-in HttpServerService. Sending smsf#httpserver#start triggers an explicit Intent to launch the service, while stop terminates it.
val intent = Intent(context, HttpServerService::class.java)
context.startService(intent)
(see lines 81-89 of SmsCommandUtils.kt)
System Operations
The system function executes privileged device actions. Before invoking reboot or shutdown, the code verifies root access via DeviceUtils.isDeviceRooted().
when (action) {
"reboot" -> DeviceUtils.reboot()
"shutdown" -> DeviceUtils.shutdown()
}
(see lines 91-116 of SmsCommandUtils.kt)
Wi-Fi Toggling
The wifi command uses the Android WifiManager to toggle the radio state. This requires no root access but does need the appropriate CHANGE_WIFI_STATE permission.
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
wifiManager.isWifiEnabled = (action == "on")
(see lines 118-124 of SmsCommandUtils.kt)
SMS Relay
The sms function parses a JSON payload to send an outbound message through a specific SIM slot. The JSON structure (SmsSendData) includes phoneNumbers, msgContent, and simSlot.
val data = Gson().fromJson(param, SmsSendData::class.java)
PhoneUtils.sendSms(data.phoneNumbers, data.msgContent, data.simSlot)
(see lines 126-155 of SmsCommandUtils.kt)
Security Mechanisms
SmsForwarder implements multiple safeguards to prevent malicious command execution:
- Safe-Phone Validation: Only numbers listed in
SettingUtils.smsCommandSafePhoneare permitted to send commands. - Root Verification: System-level commands (
reboot,shutdown) explicitly checkDeviceUtils.isDeviceRooted()before execution. - Duplicate Protection: For system commands,
HistoryUtilsmaintains a cache to prevent rapid re-execution of identical commands (lines 96-108 ofSmsCommandUtils.kt).
User Documentation
The exact syntax is documented in the user interface via res/values/strings.xml at line 373, which explains the command format to end users:
<string name="sms_command_tips">
根据短信指令开关对应功能,指令格式:smsf#功能名#动作名
</string>
Summary
- Entry Point:
SmsReceiver.ktfilters messages for thesmsf#prefix and validates senders against a safe-phone list. - Parser:
SmsCommandUtils.execute()splits commands into function-action-parameter triples using a limit of 3 splits on the#character. - Supported Commands: FRPC tunnel control, HTTP server management, system reboot/shutdown (requires root), Wi-Fi toggling, and SMS relay.
- Security Layers: Safe-phone lists, root checks for privileged operations, and historical duplicate command prevention.
Frequently Asked Questions
What is the exact format for SMS commands in SmsForwarder?
The format is smsf#<function>#<action>#<optional_parameter>. The parser splits the string on # into a maximum of three parts, where the first part is the function name (e.g., wifi, frpc), the second is the action (e.g., on, start), and the third is an optional parameter used for specific FRPC UIDs or JSON SMS payloads.
Which source file handles the parsing of smsf# commands?
The parsing logic is implemented in app/src/main/kotlin/cn/ppps/forwarder/utils/SmsCommandUtils.kt. The execute() method at line 37 performs the string splitting and dispatches to the appropriate handler via a when statement.
Does SmsForwarder require root access for all SMS commands?
No, root access is required only for system-level commands such as reboot and shutdown. The code explicitly checks DeviceUtils.isDeviceRooted() before executing these operations. Commands for Wi-Fi, FRPC, HTTP server, and SMS relay operate without root privileges.
How does SmsForwarder prevent unauthorized SMS command execution?
The app enforces authorization through a configurable safe-phone list stored in SettingUtils. Additionally, the entire command feature is gated by the boolean enableSmsCommand setting. Only messages from approved senders that begin with the smsf# prefix are processed; all others are ignored or forwarded through the normal pipeline.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →