added automatic latest firmware spoofing
This commit is contained in:
@@ -89,3 +89,28 @@ behavior that still needs manual testing.
|
|||||||
state in the handoff.
|
state in the handoff.
|
||||||
- Do not commit generated binaries, OpenWrt build output, runtime state, logs, or
|
- Do not commit generated binaries, OpenWrt build output, runtime state, logs, or
|
||||||
captured protocol payloads.
|
captured protocol payloads.
|
||||||
|
|
||||||
|
## Environment pitfalls and shared discoveries
|
||||||
|
|
||||||
|
- In this workspace, the Codex `apply_patch` helper is currently unusable. It
|
||||||
|
fails with `bwrap: No permissions to create a new namespace`, including when
|
||||||
|
invoked from an approved command outside the normal sandbox. Do not spend time
|
||||||
|
retrying it or tracing its symlink after seeing this known error.
|
||||||
|
- For repository edits, use `git apply --recount` with a focused unified diff as
|
||||||
|
the fallback. `--recount` avoids failures caused by manually miscounted hunk
|
||||||
|
lengths. Review the resulting `git diff` and run `git diff --check` afterward.
|
||||||
|
Preserve unrelated worktree changes exactly as with any other editing method.
|
||||||
|
- Ordinary read-only commands may fail with the same `bwrap` namespace error.
|
||||||
|
When the command is safe and required, rerun it using the environment's normal
|
||||||
|
escalation/approval mechanism instead of investigating the namespace setup.
|
||||||
|
|
||||||
|
Agents must preserve useful environment knowledge for later agents. When a new
|
||||||
|
pitfall or workaround is verified to be deterministic or repeatedly encountered,
|
||||||
|
add a short entry to this section before handoff. Keep these entries actionable
|
||||||
|
and specific: include the recognizable failure, the confirmed workaround, and
|
||||||
|
any validation required afterward.
|
||||||
|
|
||||||
|
Do not record transient command failures, guesses, lengthy logs, credentials,
|
||||||
|
auth keys, host secrets, or details that only apply to a single task. If a
|
||||||
|
discovery could weaken safety controls or requires broader permissions, report
|
||||||
|
it to the user instead of documenting a bypass.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Daemon that makes an OpenWrt router appear as a UniFi AP to UniFi Network contro
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| **L2 Discovery** | UDP broadcast + multicast every 10s | `announce.c` → port 10001 |
|
| **L2 Discovery** | UDP broadcast + multicast every 10s | `announce.c` → port 10001 |
|
||||||
| **Adoption** | AES-128-CBC handshake with the controller | `inform.c` → `handle_response()` |
|
| **Adoption** | AES-128-CBC handshake with the controller | `inform.c` → `handle_response()` |
|
||||||
|
| **Firmware spoofing** | Persists and reports the target version requested by an upgrade | `inform.c` → `handle_response()` |
|
||||||
| **WiFi Config** | Creates WiFi networks from the controller via UCI | `wlan.c` → `wlan_apply_config()` |
|
| **WiFi Config** | Creates WiFi networks from the controller via UCI | `wlan.c` → `wlan_apply_config()` |
|
||||||
| **Band Steering** | 802.11k/v Neighbor Reports + BSS Transition | `wlan.c` → `apply_vap()` |
|
| **Band Steering** | 802.11k/v Neighbor Reports + BSS Transition | `wlan.c` → `apply_vap()` |
|
||||||
| **Fast Roaming** | 802.11r FT with mobility_domain derived from MAC | `wlan.c` → `apply_vap()` |
|
| **Fast Roaming** | 802.11r FT with mobility_domain derived from MAC | `wlan.c` → `apply_vap()` |
|
||||||
@@ -99,6 +100,10 @@ Daemon settings live in `/etc/openuf/openuf.conf`. Adoption and controller state
|
|||||||
are persisted separately in `/etc/openuf/state.json`; do not copy that file
|
are persisted separately in `/etc/openuf/state.json`; do not copy that file
|
||||||
between devices because it contains the device authentication key.
|
between devices because it contains the device authentication key.
|
||||||
|
|
||||||
|
Because UniFi firmware cannot run on the OpenWrt host, an upgrade request does
|
||||||
|
not download or install its image. Instead, openUF saves the requested firmware
|
||||||
|
version in `state.json` and reports it in subsequent inform packets.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Glossary
|
## Glossary
|
||||||
|
|||||||
+28
-1
@@ -575,7 +575,12 @@ static char *build_payload(const openuf_state_t *st,
|
|||||||
}
|
}
|
||||||
|
|
||||||
char fw_version[64];
|
char fw_version[64];
|
||||||
snprintf(fw_version, sizeof(fw_version), "%s%s", m->fw_pre, m->fw_ver);
|
if (st->firmware_version[0])
|
||||||
|
snprintf(fw_version, sizeof(fw_version), "%s",
|
||||||
|
st->firmware_version);
|
||||||
|
else
|
||||||
|
snprintf(fw_version, sizeof(fw_version), "%s%s",
|
||||||
|
m->fw_pre, m->fw_ver);
|
||||||
|
|
||||||
char inform_url_buf[256];
|
char inform_url_buf[256];
|
||||||
if (st->inform_url[0])
|
if (st->inform_url[0])
|
||||||
@@ -812,6 +817,28 @@ static void handle_response(openuf_state_t *st,
|
|||||||
|
|
||||||
LOG("Handling response type: %s", type);
|
LOG("Handling response type: %s", type);
|
||||||
|
|
||||||
|
/* An OpenWrt host cannot install UniFi firmware. Acknowledge the
|
||||||
|
* controller's request by reporting its target version from now on. */
|
||||||
|
if (!strcmp(type, "upgrade")) {
|
||||||
|
if (json_object_object_get_ex(resp, "version", &v) &&
|
||||||
|
json_object_is_type(v, json_type_string)) {
|
||||||
|
const char *version = json_object_get_string(v);
|
||||||
|
size_t len = strlen(version);
|
||||||
|
if (len > 0 && len < sizeof(st->firmware_version)) {
|
||||||
|
snprintf(st->firmware_version,
|
||||||
|
sizeof(st->firmware_version), "%s", version);
|
||||||
|
state_save(st);
|
||||||
|
LOG("Firmware upgrade spoofed; now reporting version=%s",
|
||||||
|
st->firmware_version);
|
||||||
|
strcpy(action_out, "upgrade-spoofed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG("Ignoring upgrade response without a valid version");
|
||||||
|
strcpy(action_out, "upgrade-invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── noop ────────────────────────────────────────────────────── */
|
/* ── noop ────────────────────────────────────────────────────── */
|
||||||
if (!strcmp(type, "noop")) {
|
if (!strcmp(type, "noop")) {
|
||||||
strcpy(action_out, "noop");
|
strcpy(action_out, "noop");
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@
|
|||||||
void inform_set_debug_level(int level);
|
void inform_set_debug_level(int level);
|
||||||
|
|
||||||
/* Send one inform cycle.
|
/* Send one inform cycle.
|
||||||
* Updates *st in place (adopted flag, auth key, inform_url, cfgversion).
|
* Updates *st in place (adoption, controller config, and spoofed firmware).
|
||||||
* Returns 0 on success, -1 on error (sets err_out[0..127]). */
|
* Returns 0 on success, -1 on error (sets err_out[0..127]). */
|
||||||
int inform_send(openuf_state_t *st,
|
int inform_send(openuf_state_t *st,
|
||||||
const uf_model_t *model,
|
const uf_model_t *model,
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ void state_load(openuf_state_t *st)
|
|||||||
LOAD_STR (authkey, "authkey");
|
LOAD_STR (authkey, "authkey");
|
||||||
LOAD_STR (inform_url, "inform_url");
|
LOAD_STR (inform_url, "inform_url");
|
||||||
LOAD_STR (cfgversion, "cfgversion");
|
LOAD_STR (cfgversion, "cfgversion");
|
||||||
|
LOAD_STR (firmware_version, "firmware_version");
|
||||||
LOAD_BOOL(config_applied, "config_applied");
|
LOAD_BOOL(config_applied, "config_applied");
|
||||||
LOAD_INT (config_schema, "config_schema");
|
LOAD_INT (config_schema, "config_schema");
|
||||||
LOAD_BOOL(use_aes_gcm, "use_aes_gcm");
|
LOAD_BOOL(use_aes_gcm, "use_aes_gcm");
|
||||||
@@ -112,6 +113,7 @@ int state_save(const openuf_state_t *st)
|
|||||||
json_object_object_add(root, "authkey", json_object_new_string(st->authkey));
|
json_object_object_add(root, "authkey", json_object_new_string(st->authkey));
|
||||||
json_object_object_add(root, "inform_url", json_object_new_string(st->inform_url));
|
json_object_object_add(root, "inform_url", json_object_new_string(st->inform_url));
|
||||||
json_object_object_add(root, "cfgversion", json_object_new_string(st->cfgversion));
|
json_object_object_add(root, "cfgversion", json_object_new_string(st->cfgversion));
|
||||||
|
json_object_object_add(root, "firmware_version", json_object_new_string(st->firmware_version));
|
||||||
json_object_object_add(root, "config_applied", json_object_new_boolean(st->config_applied));
|
json_object_object_add(root, "config_applied", json_object_new_boolean(st->config_applied));
|
||||||
json_object_object_add(root, "config_schema", json_object_new_int(st->config_schema));
|
json_object_object_add(root, "config_schema", json_object_new_int(st->config_schema));
|
||||||
json_object_object_add(root, "use_aes_gcm", json_object_new_boolean(st->use_aes_gcm));
|
json_object_object_add(root, "use_aes_gcm", json_object_new_boolean(st->use_aes_gcm));
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ typedef struct {
|
|||||||
char authkey[64];
|
char authkey[64];
|
||||||
char inform_url[256];
|
char inform_url[256];
|
||||||
char cfgversion[32];
|
char cfgversion[32];
|
||||||
|
char firmware_version[64];
|
||||||
bool config_applied;
|
bool config_applied;
|
||||||
int config_schema;
|
int config_schema;
|
||||||
bool use_aes_gcm;
|
bool use_aes_gcm;
|
||||||
|
|||||||
Reference in New Issue
Block a user