diff --git a/update_mac.c b/update_mac.c index 170c4e4..b0e24cc 100644 --- a/update_mac.c +++ b/update_mac.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "hiredis.h" // 前置声明:黄灯控制接口 @@ -339,6 +340,100 @@ static int redis_query_mac(const char* host_opt, const char* port_opt, const cha return -1; } +// 审计:在Redis记录每次使用的MAC、批次与时间 +static int redis_audit_log(const char* host_opt, const char* port_opt, const char* db_opt, + const char* audit_key_opt, const char* batch, const char* mac, const char* note_opt) { + if (!batch || !*batch || !mac || !*mac) return -1; + + const char* host = host_opt ? host_opt : (getenv("REDIS_HOST") ? getenv("REDIS_HOST") : "180.163.74.83"); + int port = port_opt ? atoi(port_opt) : (getenv("REDIS_PORT") ? atoi(getenv("REDIS_PORT")) : 6379); + int db = db_opt ? atoi(db_opt) : (getenv("REDIS_DB") ? atoi(getenv("REDIS_DB")) : 0); + const char* auth = getenv("REDIS_AUTH"); + if (!auth || !*auth) auth = "Zzh08165511"; + const char* audit_key = audit_key_opt ? audit_key_opt : (getenv("REDIS_AUDIT_KEY") ? getenv("REDIS_AUDIT_KEY") : "mac_batch_audit_pdd"); + + struct timeval tv; tv.tv_sec = 3; tv.tv_usec = 0; + redisContext* c = redisConnectWithTimeout(host, port, tv); + if (!c || c->err) { + fprintf(stderr, "[redis-audit] connect error: %s\n", c ? c->errstr : "unknown"); + if (c) redisFree(c); + return -1; + } + + if (auth && *auth) { + redisReply* ra = (redisReply*)redisCommand(c, "AUTH %s", auth); + if (!ra || (ra->type == REDIS_REPLY_ERROR)) { + fprintf(stderr, "[redis-audit] AUTH error: %s\n", ra && ra->str ? ra->str : "no-reply"); + if (ra) freeReplyObject(ra); + redisFree(c); + return -1; + } + freeReplyObject(ra); + } + + if (db > 0) { + redisReply* rs = (redisReply*)redisCommand(c, "SELECT %d", db); + if (!rs || (rs->type == REDIS_REPLY_ERROR)) { + fprintf(stderr, "[redis-audit] SELECT %d error: %s\n", db, rs && rs->str ? rs->str : "no-reply"); + if (rs) freeReplyObject(rs); + redisFree(c); + return -1; + } + freeReplyObject(rs); + } + + // 优先使用 Redis 服务器时间,避免设备本地时间不准 + long long sv_secs = -1; + { + redisReply* tr = (redisReply*)redisCommand(c, "TIME"); + if (tr && tr->type == REDIS_REPLY_ARRAY && tr->elements >= 2 && + tr->element[0] && tr->element[0]->str) { + sv_secs = atoll(tr->element[0]->str); + } else { + fprintf(stderr, "[redis-audit] TIME failed, fallback to local time\n"); + } + if (tr) freeReplyObject(tr); + } + + time_t base = (sv_secs > 0) ? (time_t)sv_secs : time(NULL); + // 中国时区(+08:00),不依赖设备TZ;格式为 YYYY-MM-DD HH:MM:SS + time_t base_cn = base + 8 * 3600; + struct tm tm_sv_cn; gmtime_r(&base_cn, &tm_sv_cn); + char ts_cn[24]; + strftime(ts_cn, sizeof(ts_cn), "%Y-%m-%d %H:%M:%S", &tm_sv_cn); + + char val[320]; + snprintf(val, sizeof(val), "ts_cn=%s batch=%s mac=%s%s%s", ts_cn, batch, mac, + (note_opt && *note_opt) ? " note=" : "", + (note_opt && *note_opt) ? note_opt : ""); + + // 写入总审计列表 + redisReply* r = (redisReply*)redisCommand(c, "LPUSH %s %s", audit_key, val); + if (!r || r->type == REDIS_REPLY_ERROR) { + fprintf(stderr, "[redis-audit] LPUSH %s failed: %s\n", audit_key, r && r->str ? r->str : "no-reply"); + if (r) freeReplyObject(r); + redisFree(c); + return -1; + } + freeReplyObject(r); + + // 同时按批次维度记录,key为 : + char batch_key[128]; + snprintf(batch_key, sizeof(batch_key), "%s:%s", audit_key, batch); + r = (redisReply*)redisCommand(c, "LPUSH %s %s", batch_key, val); + if (!r || r->type == REDIS_REPLY_ERROR) { + fprintf(stderr, "[redis-audit] LPUSH %s failed: %s\n", batch_key, r && r->str ? r->str : "no-reply"); + if (r) freeReplyObject(r); + redisFree(c); + return -1; + } + freeReplyObject(r); + + redisFree(c); + fprintf(stderr, "[redis-audit] logged: %s | %s\n", batch, mac); + return 0; +} + static int read_file(const char* path, char** out_buf, size_t* out_len) { FILE* f = fopen(path, "rb"); if (!f) return -1; @@ -583,6 +678,8 @@ int main(int argc, char** argv) { if (update_hwaddress_in_interfaces(interfaces_path, mac_from_redis) == 0) { stop_yellow_blink(); fprintf(stdout, "已更新MAC为: %s\n", mac_from_redis); + // 记录审计:批次、MAC、时间 + redis_audit_log(NULL, NULL, NULL, NULL, batch, mac_from_redis, "auto-loop"); sync(); char verify_mac[64] = {0}; if (get_hw_mac_from_interfaces(interfaces_path, verify_mac, sizeof(verify_mac)) == 0) { @@ -656,6 +753,8 @@ int main(int argc, char** argv) { if (update_hwaddress_in_interfaces(interfaces_path, mac_from_redis) != 0) { return 3; } + // 记录审计:批次、MAC、时间 + redis_audit_log(NULL, NULL, NULL, NULL, batch, mac_from_redis, "legacy"); char verify_mac[64] = {0}; if (get_hw_mac_from_interfaces(interfaces_path, verify_mac, sizeof(verify_mac)) == 0) { to_upper_str(verify_mac); @@ -698,10 +797,10 @@ static pthread_t led_thread; static void gpio_init_yellow(void) { int fd = open("/sys/class/gpio/export", O_WRONLY); if (fd >= 0) { - write(fd, "114", 3); + write(fd, "113", 3); close(fd); } - fd = open("/sys/class/gpio/gpio114/direction", O_WRONLY); + fd = open("/sys/class/gpio/gpio113/direction", O_WRONLY); if (fd >= 0) { write(fd, "out", 3); close(fd); @@ -709,7 +808,7 @@ static void gpio_init_yellow(void) { } static void* led_blink_thread(void* arg) { - int fd = open("/sys/class/gpio/gpio114/value", O_WRONLY); + int fd = open("/sys/class/gpio/gpio113/value", O_WRONLY); if (fd < 0) return NULL; while (led_running) { write(fd, "1", 1); @@ -742,7 +841,7 @@ static void set_yellow_on(void) { stop_yellow_blink(); // 初始化GPIO并置为高电平 gpio_init_yellow(); - int fd = open("/sys/class/gpio/gpio114/value", O_WRONLY); + int fd = open("/sys/class/gpio/gpio113/value", O_WRONLY); if (fd < 0) return; write(fd, "1", 1); close(fd); diff --git a/update_mac_pdd b/update_mac_pdd index bdcc4b1..7531de0 100755 Binary files a/update_mac_pdd and b/update_mac_pdd differ