// // Created by xajhuang on 2022/5/10. // #include #include #include #include #include "pppoe_session.h" #include "netif/ppp/ppp.h" #include "netif/ppp/pppoe.h" #include "netif/pppoeif.h" #include "misc.h" #include "user_errno.h" #include "netif/ppp/pppapi.h" #include "config.h" #include "msg_queue.h" #include "vxlan_pkg.h" #include "netif/pcapif.h" #include "s2j/cJSON.h" typedef struct PPPOE_CACHE { PPPPOE_SESSION_DATA pSessionData; int nextStatus; PUSER_INFO_CONTEXT pUser; struct PPPOE_CACHE *next, *prev; } PPPOE_CACHE, *PPPPOE_CACHE; struct PPPOE_ERR_INFO_ { int errid; const char *errmsg; } g_pppoeErr[] = { {PPPERR_NONE, "No error"}, {PPPERR_PARAM, "Invalid parameter"}, {PPPERR_OPEN, "Unable to open PPP session"}, {PPPERR_DEVICE, "Invalid I/O device for PPP"}, {PPPERR_ALLOC, "Unable to allocate resources"}, {PPPERR_USER, "User interrupt"}, {PPPERR_CONNECT, "Connection lost"}, {PPPERR_AUTHFAIL, "Failed authentication challenge"}, {PPPERR_PROTOCOL, "Failed to meet protocol"}, {PPPERR_PEERDEAD, "Connection timeout"}, {PPPERR_IDLETIMEOUT, "Idle Timeout"}, {PPPERR_CONNECTTIME, "Max connect time reach max time"}, {PPPERR_LOOPBACK, "Loopback detect"}, }; static struct netif *g_rawSocketIf = NULL; static PPPPOE_CACHE g_pPPPCache = NULL; static PPPPOE_CACHE g_pPPPDelete = NULL; static uv_rwlock_t g_cacheLock; static void pppLinkStatusCallback(ppp_pcb *pcb, int errCode, void *ctx) { PPPPOE_CACHE pCache; struct netif *pppif = ppp_netif(pcb); struct pppoe_softc *sc = (struct pppoe_softc *)pcb->link_ctx_cb; PUSER_INFO_CONTEXT pUser = (PUSER_INFO_CONTEXT)ctx; switch (errCode) { case PPPERR_NONE: { /* No error. */ pCache = (PPPPOE_CACHE)malloc(sizeof(PPPOE_CACHE)); dzlog_info("<%p> PPPoE user(%05d:%s) connect server succeeded[%08X], Session: %04X\n", pcb, pUser->userid, pUser->user_info.pppoe_user, pcb->lcp_gotoptions.magicnumber, sc->sc_session); #if LWIP_IPV4 pUser->session.data.sessionId = sc->sc_session; strncpy(pUser->session.data.clientIp, ip4addr_ntoa(netif_ip4_addr(pppif)), MAX_IP_V4_STR); strncpy(pUser->session.data.clientGw, ip4addr_ntoa(netif_ip4_gw(pppif)), MAX_IP_V4_STR); strncpy(pUser->session.data.clientMask, ip4addr_ntoa(netif_ip4_netmask(pppif)), MAX_IP_V4_STR); sprintf(pUser->session.data.clientMac, "%02X:%02X:%02X:%02X:%02X:%02X", pUser->user_info.mac_addr[0], pUser->user_info.mac_addr[1], pUser->user_info.mac_addr[2], pUser->user_info.mac_addr[3], pUser->user_info.mac_addr[4], pUser->user_info.mac_addr[5]); dzlog_info(" our_ipaddr = %s\n", pUser->session.data.clientIp); dzlog_info(" his_ipaddr = %s\n", pUser->session.data.clientGw); dzlog_info(" netmask = %s\n", pUser->session.data.clientMask); #endif /* LWIP_IPV4 */ #if LWIP_DNS dzlog_info(" dns1 = %s\n", ipaddr_ntoa(dns_getserver(0))); dzlog_info(" dns2 = %s\n", ipaddr_ntoa(dns_getserver(1))); #endif /* LWIP_DNS */ #if PPP_IPV6_SUPPORT dzlog_info(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); #endif /* PPP_IPV6_SUPPORT */ if (pCache) { pCache->pSessionData = &pUser->session.data; pCache->pUser = pUser; uv_rwlock_wrlock(&g_cacheLock); LL_APPEND(g_pPPPCache, pCache); uv_rwlock_wrunlock(&g_cacheLock); } pUser->session.status = STATUS_TASK_CONNECTED; break; } case PPPERR_PARAM: case PPPERR_AUTHFAIL: case PPPERR_PROTOCOL: dzlog_error("<%p> pppLinkStatusCallback: %s(%d)", pcb, g_pppoeErr[errCode].errmsg, g_pppoeErr[errCode].errid); if (pUser->session.status != STATUS_TASK_DELETE) { if (pUser->session.status == STATUS_TASK_CONNECTED) { pCache = (PPPPOE_CACHE)malloc(sizeof(PPPOE_CACHE)); if (pCache) { pCache->pSessionData = &pUser->session.data; pCache->pUser = pUser; pCache->nextStatus = STATUS_TASK_ERROR; uv_rwlock_wrlock(&g_cacheLock); LL_APPEND(g_pPPPDelete, pCache); uv_rwlock_wrunlock(&g_cacheLock); } else { pUser->session.status = STATUS_TASK_ERROR; } } else { pUser->session.status = STATUS_TASK_ERROR; } } break; case PPPERR_USER: dzlog_info("User(%05d:%s) disconnect\n", pUser->userid, pUser->user_info.pppoe_user); pCache = (PPPPOE_CACHE)malloc(sizeof(PPPOE_CACHE)); if (pCache) { pCache->pSessionData = &pUser->session.data; pCache->pUser = pUser; pCache->nextStatus = pUser->session.status; uv_rwlock_wrlock(&g_cacheLock); LL_APPEND(g_pPPPDelete, pCache); uv_rwlock_wrunlock(&g_cacheLock); } break; case PPPERR_OPEN: case PPPERR_DEVICE: case PPPERR_ALLOC: case PPPERR_CONNECT: case PPPERR_PEERDEAD: case PPPERR_IDLETIMEOUT: case PPPERR_CONNECTTIME: case PPPERR_LOOPBACK: dzlog_error("<%p> pppLinkStatusCallback: %s(%d)\n", pcb, g_pppoeErr[errCode].errmsg, g_pppoeErr[errCode].errid); if (pUser->session.status != STATUS_TASK_DELETE) { if (pUser->session.status == STATUS_TASK_CONNECTED) { pCache = (PPPPOE_CACHE)malloc(sizeof(PPPOE_CACHE)); if (pCache) { pCache->pSessionData = &pUser->session.data; pCache->pUser = pUser; pCache->nextStatus = STATUS_TASK_ERROR; uv_rwlock_wrlock(&g_cacheLock); LL_APPEND(g_pPPPDelete, pCache); uv_rwlock_wrunlock(&g_cacheLock); } else { pUser->session.status = STATUS_TASK_DISCONNECTED; } } else { pUser->session.status = STATUS_TASK_DISCONNECTED; } } break; default: { printf("<%p> pppLinkStatusCallback: unknown errCode %d\n", pcb, errCode); break; } } } _Noreturn void sessionCalcCb(void *UNUSED(pArg)) { do { PUSER_INFO_CONTEXT pUserList = get_all_user_by_id(); PUSER_INFO_CONTEXT pUser, pTmp; uv_rwlock_rdlock(get_user_lock()); HASH_ITER(hh_id, pUserList, pUser, pTmp) { PPPPOE_SESSION pSession = &pUser->session; switch (pSession->status) { case STATUS_TASK_INIT: if (pppoe_session_create(pUser) == ERR_SUCCESS) { dzlog_debug("User(%05d:%s) init pppoe session\n", pUser->userid, pUser->user_info.pppoe_user); pSession->status = STATUS_TASK_DIAL; } break; case STATUS_TASK_DIAL: if (pUser->session.retry.timeout == 0) { dzlog_debug("User(%05d:%s) connect PPPoE server\n", pUser->userid, pUser->user_info.pppoe_user); pppapi_connect(pSession->ppp, 0); pUser->session.retry.timeout = time(NULL) + PPPOE_MAX_TIMEOUT; } else if (time(NULL) > pUser->session.retry.timeout) { pUser->session.retry.timeout = 0; } break; case STATUS_TASK_ERROR: if (pUser->session.retry.timeout == 0) { dzlog_error("User(%05d:%s) PPPoE dial error Invalid parameter\n", pUser->userid, pUser->user_info.pppoe_user); // 10秒后尝试重新拨号 pUser->session.retry.timeout = time(NULL) + (PPPOE_MAX_TIMEOUT / 2); pUser->session.retry.count = 0; } else if (time(NULL) > pUser->session.retry.timeout) { dzlog_warn("User(%05d:%s) retry dial %u times\n", pUser->userid, pUser->user_info.pppoe_user, pUser->session.retry.count); pUser->session.retry.timeout = 0; pUser->session.retry.count++; // 下次重新拨号 pSession->status = STATUS_TASK_DIAL; } break; case STATUS_TASK_DISCONNECTED: dzlog_error("User %s disconnect, auto reconnect\n", pUser->user_info.pppoe_user); // 自动重新拨号 pSession->status = STATUS_TASK_DIAL; break; case STATUS_TASK_DELETE: if (pUser->session.retry.timeout == 0) { dzlog_debug("User(%05d:%s) PPPoE deleted\n", pUser->userid, pUser->user_info.pppoe_user); pppapi_close(pUser->session.ppp, 0); pUser->session.retry.timeout = time(NULL); pppapi_free(pUser->session.ppp); } break; #if 0 case STATUS_TASK_CONNECTED: if (pUser->session.retry.timeout == 0) { pUser->session.retry.timeout = time(NULL) + 30; } else if (time(NULL) > pUser->session.retry.timeout) { dzlog_debug("User(%05d:%s) PPPoE disconnected\n", pUser->userid, pUser->user_info.pppoe_user); pSession->status = STATUS_TASK_DELETE; pppapi_close(pUser->session.ppp, 0); pUser->session.retry.timeout = 0; } break; #endif default: break; } } uv_rwlock_rdunlock(get_user_lock()); uv_sleep(1000); } while (TRUE); } _Noreturn void cacheCalcCb(void *UNUSED(pArg)) { do { PPPPOE_CACHE pCache, pTmp; int count; uv_rwlock_rdlock(&g_cacheLock); LL_COUNT(g_pPPPCache, pCache, count); uv_rwlock_rdunlock(&g_cacheLock); if (count > 0) { const char *pJsonString; cJSON *pRoot = cJSON_CreateObject(); cJSON *pSession = cJSON_CreateArray(); cJSON_AddStringToObject(pRoot, "message", "add-ywg-pppoe"); uv_rwlock_wrlock(&g_cacheLock); LL_FOREACH_SAFE(g_pPPPCache, pCache, pTmp) { cJSON *pItem = cJSON_CreateObject(); cJSON_AddNumberToObject(pItem, "sessionId", pCache->pSessionData->sessionId); cJSON_AddStringToObject(pItem, "clientIp", pCache->pSessionData->clientIp); cJSON_AddStringToObject(pItem, "clientGw", pCache->pSessionData->clientGw); cJSON_AddStringToObject(pItem, "clientMask", pCache->pSessionData->clientMask); cJSON_AddStringToObject(pItem, "clientMac", pCache->pSessionData->clientMac); cJSON_AddStringToObject(pItem, "localMac", pCache->pSessionData->svrBaseMac); cJSON_AddItemToArray(pSession, pItem); LL_DELETE(g_pPPPCache, pCache); free(pCache); } uv_rwlock_wrunlock(&g_cacheLock); cJSON_AddItemToObject(pRoot, "params", pSession); pJsonString = cJSON_PrintUnformatted(pRoot); mq_data_send_msg(pJsonString); cJSON_Delete(pRoot); free((void *)pJsonString); } uv_rwlock_rdlock(&g_cacheLock); LL_COUNT(g_pPPPDelete, pCache, count); uv_rwlock_rdunlock(&g_cacheLock); if (count > 0) { const char *pJsonString; cJSON *pRoot = cJSON_CreateObject(); cJSON *pSession = cJSON_CreateArray(); cJSON_AddStringToObject(pRoot, "message", "remove-ywg-pppoe"); uv_rwlock_wrlock(&g_cacheLock); LL_FOREACH_SAFE(g_pPPPDelete, pCache, pTmp) { cJSON *pItem = cJSON_CreateObject(); cJSON_AddNumberToObject(pItem, "sessionId", pCache->pSessionData->sessionId); cJSON_AddStringToObject(pItem, "clientMac", pCache->pSessionData->clientMac); cJSON_AddItemToArray(pSession, pItem); pCache->pUser->session.status = pCache->nextStatus; LL_DELETE(g_pPPPDelete, pCache); free(pCache); } uv_rwlock_wrunlock(&g_cacheLock); cJSON_AddItemToObject(pRoot, "params", pSession); pJsonString = cJSON_PrintUnformatted(pRoot); mq_data_send_msg(pJsonString); cJSON_Delete(pRoot); free((void *)pJsonString); } uv_sleep(1000); } while (TRUE); } int pppoe_session_init() { static uv_thread_t uvThread, cacheThread; uv_rwlock_init(&g_cacheLock); g_rawSocketIf = bind_pcap_if(config_get_vxlan_nic_name(), config_get_vxlan_pkg_filter(), cfg_get_support_vxlan()); if (g_rawSocketIf) { dzlog_info("Create hardware netif: <%p>\n", (void *)g_rawSocketIf); } else { dzlog_info("Create hardware error: <%p>\n", (void *)g_rawSocketIf); } // 启动Session状态机线程 uv_thread_create(&uvThread, sessionCalcCb, NULL); uv_thread_create(&cacheThread, cacheCalcCb, NULL); return ERR_SUCCESS; } int pppoe_session_create(PUSER_INFO_CONTEXT pUser) { ppp_pcb *ppp; struct netif *netif; struct netif *ppp_netif = (struct netif *)malloc(sizeof(struct netif)); if (ppp_netif == NULL) { dzlog_error("Malloc %lu bytes memory error\n", sizeof(struct netif)); return -ERR_MALLOC_MEMORY; } netif = create_pppoe_if(pUser); if (netif == NULL) { dzlog_error("Create PPPoE netif error: %u\n", pUser->userid); free((void *)ppp_netif); return -ERR_CREATE_PPPOE_NETIF; } pUser->session.nicif = netif; pUser->session.pppif = ppp_netif; ppp = pppapi_pppoe_create(pUser->session.pppif, pUser->session.nicif, NULL, NULL, pppLinkStatusCallback, pUser); if (ppp == NULL) { dzlog_error("Create PPPoE session error: %u\n", pUser->userid); netif_remove(netif); free((void *)ppp_netif); return -ERR_CREATE_PPP_SESSION; } pUser->session.ppp = ppp; ppp_set_auth(ppp, PPPAUTHTYPE_ANY, pUser->user_info.pppoe_user, pUser->user_info.pppoe_passwd); dzlog_debug("Create PPPoE netif %p: %u(%c%c:%u, %c%c:%u)\n", ppp, pUser->userid, ppp_netif->name[0], ppp_netif->name[1], ppp_netif->num, netif->name[0], netif->name[1], netif->num); return ERR_SUCCESS; } struct netif *get_rawsocket_if(void) { return g_rawSocketIf; }