// // Created by dongwenzhe on 2022/10/9. // #include #include using namespace std; #include #include #include #include #include #include "opendhcpd.h" #include "s2j/cJSON.h" #include "misc.h" #include #include "config.h" #include "proto.h" #include "user_errno.h" #include "uthash/uthash.h" #include "sds/sds.h" #include "inet_misc.h" #include "http_svr.h" #include "task_manager.h" #if DISCOVER_RSP_NOT_BOARDCAST #include #include #include #endif extern data2 cfig; extern bool kRunning; extern dhcpMap dhcpCache; extern time_t t; extern data71 lump; typedef struct { char iptvMAC[64]; unsigned int vni; int isReport; UT_hash_handle hh; } IPTV_DEV_SET, *PIPTV_DEV_SET; static PIPTV_DEV_SET g_iptvNewDevs = nullptr; static PIPTV_DEV_SET g_iptvCacheDevs = nullptr; static uv_rwlock_t g_uvCacheLock; #ifdef JSON_SCHEMA_ON // clang-format off typedef struct { const char *pSchJson; const char *pErrMsg; } JSON_POST_CTX; static JSON_POST_CTX g_add_msg[] = { {R"({"type":"object","required":["rangeSet"]})", "Missing required field [rangeSet]"}, {R"({"properties":{"rangeSet":{"type":"array","minItems":1}}})", "No content in array [rangeSet]"}, {R"({"properties":{"rangeSet":{"items":{"type":"object","required":["dhcpRange"]}}}})", "Missing required field [dhcpRange]"}, {R"({"properties":{"rangeSet":{"items":{"properties":{"netmask":{"type":"string"}}}}}})", "[netmask] should be a string value"}, {R"({"properties":{"rangeSet":{"items":{"properties":{"domainServer":{"type":"string"}}}}}})", "[domainServer] should be a string value"}, {R"({"properties":{"rangeSet":{"items":{"properties":{"gateway":{"type":"string"}}}}}})", "[gateway] should be a string value"}, {R"({"properties":{"rangeSet":{"items":{"properties":{"leaseTime":{"type":"integer"}}}}}})", "[leaseTime] should be an integer value"}, // {R"({"properties":{"rangeSet":{"items":{"properties":{"dhcpRange":{"type":"string","minLength":15}}}}}})", "Error in field [dhcpRange]"} }; static JSON_POST_CTX g_del_msg[] = { {R"({"type":"object","required":["dhcpRange"]})", "Missing required field [dhcpRange]"}, {R"({"properties":{"dhcpRange":{"type":"array","minItems":1}}})", "No content in field [dhcpRange]"}, // {R"({"properties":{"dhcpRange":{"items":{"type":"string","minLength":15}}}})", "Error in field [dhcpRange]"} }; static JSON_POST_CTX g_que_msg[] = { {R"({"type":"object","required":["userMac"]})", "Missing required field [userMac]"}, {R"({"properties":{"userMac":{"type":"array","minItems":1}}})", "No content in field [userMac]"}, // {R"({"properties":{"userMac":{"items":{"type":"string","minLength":17,"maxLength":17}}}})", "Error in field [userMac]"} }; // clang-format on #endif static int dhcp_get_user_info(const char **pRsp, const char *pRequest) { char logBuff[512]; const char *pStrContent; int k; int errCode = 0; dhcpMap::iterator p; if (pRequest == nullptr || strlen(pRequest) == 0) { sprintf(logBuff, "Request Json"); logDHCPMess(logBuff, 1); return ERR_INPUT_PARAMS; } pStrContent = proto_decode_context(pRequest, nullptr, nullptr, &errCode); if (pStrContent == nullptr) { sprintf(logBuff, "Request Json error %s", pRequest); logDHCPMess(logBuff, 1); free((void *)pStrContent); return ERR_PROTO_DECODE; } #ifdef JSON_SCHEMA_ON if (errCode == ERR_JSON_VALID_SCH) { *pRsp = pStrContent; return ERR_SUCCESS; } const char *pSchJson; for(auto i : g_que_msg) { pSchJson = proto_msg_validation(pStrContent, i.pSchJson, i.pErrMsg); if (pSchJson != nullptr && strlen(pSchJson) > 0) { *pRsp = pSchJson; free((void *)pStrContent); return ERR_SUCCESS; } } free((void *)pSchJson); #endif cJSON *pRoot = cJSON_Parse(pStrContent); free((void *)pStrContent); if (!pRoot) { return ERR_JSON_PARSE_OBJ; } cJSON *pUserMac = cJSON_GetObjectItem(pRoot, "userMac"); if (!pUserMac) { cJSON_Delete(pRoot); return ERR_JSON_PARSE_OBJ; } cJSON *pRspMsg = cJSON_CreateObject(); cJSON *pMsgArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspMsg, "userInfo", pMsgArray); k = cJSON_GetArraySize(pUserMac); // 传入数据 userMac 为空数组时,返回所有用户数据 if (k == 0) { for (p = dhcpCache.begin(); p != dhcpCache.end(); p++) { char tempbuff[512]; data7 *dhcpEntry = p->second; if (!dhcpEntry) { continue; } cJSON *pRspItem = cJSON_CreateObject(); cJSON_AddStringToObject(pRspItem, "userMac", dhcpEntry->mapname); cJSON_AddStringToObject(pRspItem, "ip", IP2String(tempbuff, dhcpEntry->ip)); cJSON_AddStringToObject(pRspItem, "hostname", dhcpEntry->hostname); if (dhcpEntry->display && dhcpEntry->expiry >= t) { tm *ttm = localtime(&dhcpEntry->expiry); strftime(tempbuff, sizeof(tempbuff), "%d-%b-%y %X", ttm); cJSON_AddStringToObject(pRspItem, "leaseExpiry", tempbuff); } else { cJSON_AddStringToObject(pRspItem, "leaseExpiry", "Expiry"); } cJSON_AddNumberToObject(pRspItem, "status", ERR_SUCCESS); cJSON_AddStringToObject(pRspItem, "message", getErrorEnumDesc(ERR_SUCCESS)); cJSON_AddItemToArray(pMsgArray, pRspItem); } } else { for (int i = 0; i < k; i++) { char tempbuff[512]; cJSON *pItem = cJSON_GetArrayItem(pUserMac, i); cJSON *pRspItem = cJSON_CreateObject(); p = dhcpCache.find(pItem->valuestring); cJSON_AddStringToObject(pRspItem, "userMac", pItem->valuestring); if (p != dhcpCache.end()) { data7 *dhcpEntry = p->second; cJSON_AddStringToObject(pRspItem, "ip", IP2String(tempbuff, dhcpEntry->ip)); cJSON_AddStringToObject(pRspItem, "hostname", dhcpEntry->hostname); if (dhcpEntry->display && dhcpEntry->expiry >= t) { tm *ttm = localtime(&dhcpEntry->expiry); strftime(tempbuff, sizeof(tempbuff), "%d-%b-%y %X", ttm); cJSON_AddStringToObject(pRspItem, "leaseExpiry", tempbuff); } else { cJSON_AddStringToObject(pRspItem, "leaseExpiry", "Expiry"); } cJSON_AddNumberToObject(pRspItem, "status", ERR_SUCCESS); cJSON_AddStringToObject(pRspItem, "message", getErrorEnumDesc(ERR_SUCCESS)); } else { cJSON_AddNumberToObject(pRspItem, "status", ERR_ITEM_UNEXISTS); cJSON_AddStringToObject(pRspItem, "message", getErrorEnumDesc(ERR_ITEM_UNEXISTS)); } cJSON_AddItemToArray(pMsgArray, pRspItem); } } *pRsp = proto_create_new(pRspMsg, 200); cJSON_Delete(pRoot); return ERR_SUCCESS; } static int dchp_get_all_iptv_devs(const char **pRsp) { char logBuff[512]; PIPTV_DEV_SET pDev, pTemp; cJSON *pRspMsg = cJSON_CreateObject(); cJSON *pMsgArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspMsg, "iptvDevs", pMsgArray); uv_rwlock_wrlock(&g_uvCacheLock); HASH_ITER(hh, g_iptvCacheDevs, pDev, pTemp) { cJSON *pRspItem = cJSON_CreateObject(); cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); cJSON_AddBoolToObject(pRspItem, "reported", pDev->isReport); cJSON_AddItemToArray(pMsgArray, pRspItem); } HASH_ITER(hh, g_iptvNewDevs, pDev, pTemp) { cJSON *pRspItem = cJSON_CreateObject(); cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); cJSON_AddBoolToObject(pRspItem, "reported", pDev->isReport); cJSON_AddItemToArray(pMsgArray, pRspItem); } uv_rwlock_wrunlock(&g_uvCacheLock); cJSON_AddNumberToObject(pRspMsg, "status", ERR_SUCCESS); cJSON_AddStringToObject(pRspMsg, "message", getErrorEnumDesc(ERR_SUCCESS)); *pRsp = proto_create_new(pRspMsg, 200); return ERR_SUCCESS; } static int dhcp_get_all_user(const char **pRsp) { char logBuff[512]; data7 *dhcpEntry; dhcpMap::iterator p; cJSON *pRspMsg = cJSON_CreateObject(); cJSON *pMsgArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspMsg, "users", pMsgArray); for (p = dhcpCache.begin(); kRunning && p != dhcpCache.end(); p++) { if ((dhcpEntry = p->second)) { cJSON_AddStringToObject(pMsgArray, "", dhcpEntry->mapname); } } cJSON_AddNumberToObject(pRspMsg, "status", ERR_SUCCESS); cJSON_AddStringToObject(pRspMsg, "message", getErrorEnumDesc(ERR_SUCCESS)); *pRsp = proto_create_new(pRspMsg, 200); return ERR_SUCCESS; } #define VALUE_TO_DHCP_TLV(buf, val, tag) \ do { \ int valSize; \ int numbytes = myTokenize((buf), (val), "/,.", true); \ if (numbytes <= 255) { \ char *ptr = (buf); \ valSize = 0; \ for (; *ptr; ptr = myGetToken(ptr, 1)) { \ if (isInt(ptr)) { \ hoption[valSize] = STR2INT(ptr); \ valSize++; \ } else { \ break; \ } \ } \ memcpy((val), hoption, valSize); \ if (buffSize > valSize + 2) { \ *dp = (tag); \ dp++; \ *dp = valSize; \ dp++; \ memcpy(dp, (val), valSize); \ dp += valSize; \ buffSize -= (valSize + 2); \ } \ } \ } while (0) static int dhcp_add_rangeset_to_options(POBJ_DHCP_RNG pRange) { int ret; char buff[1024]; MYBYTE hoption[256]; MYBYTE *dp; MYWORD buffSize = sizeof(dhcp_packet) - sizeof(dhcp_header); char value[256] = {0}; MYBYTE *options = nullptr; data20 optionData {}; if (!pRange) { return -ERR_INPUT_PARAMS; } memset(&optionData, 0, sizeof(data20)); optionData.rangeSetInd = cfig.rangeCount; cfig.rangeSet[cfig.rangeCount].active = true; dp = optionData.options; *dp = 0; dp++; //dhcp_range ret = addDHCPRange(pRange->rangAddr); if (ret != ERR_SUCCESS) { return ret; } if (strlen(pRange->subnet) != 0) { strcpy(value, pRange->subnet); VALUE_TO_DHCP_TLV(buff, value, DHCP_OPTION_NETMASK); optionData.mask = (*((MYDWORD *)value)); } if (strlen(pRange->dnsSvr) != 0) { strcpy(value, pRange->dnsSvr); VALUE_TO_DHCP_TLV(buff, value, DHCP_OPTION_DNS); } if (strlen(pRange->gateway) != 0) { strcpy(value, pRange->gateway); VALUE_TO_DHCP_TLV(buff, value, DHCP_OPTION_ROUTER); } //lease if (pRange->lease != 0) { MYDWORD j; j = pRange->lease; if (buffSize > 6) { *dp = DHCP_OPTION_IPADDRLEASE; dp++; *dp = 4; dp++; dp += pUInt(dp, j); } } *dp = DHCP_OPTION_END; dp++; optionData.optionSize = (dp - optionData.options); if (optionData.optionSize > 3) { options = (MYBYTE *)calloc(1, optionData.optionSize); memcpy(options, optionData.options, optionData.optionSize); } cfig.dhcpRanges[cfig.rangeCount].rangeSetInd = optionData.rangeSetInd; cfig.dhcpRanges[cfig.rangeCount].options = options; cfig.dhcpRanges[cfig.rangeCount].mask = optionData.mask; if (!cfig.dhcpRanges[cfig.rangeCount].mask) { cfig.dhcpRanges[cfig.rangeCount].mask = cfig.mask; } cfig.rangeCount = (char)(cfig.rangeCount + 1); return ERR_SUCCESS; } static int add_dhcpd_rangeset(const char **pRsp, const char *pRequest) { char logBuff[512]; const char *pStrContent; OBJ_DHCP_RNG range; cJSON *pRspRoot; cJSON *pExpandArray; int errCode = 0; if (pRequest == nullptr || strlen(pRequest) == 0) { sprintf(logBuff, "Request Json"); logDHCPMess(logBuff, 1); return ERR_INPUT_PARAMS; } pStrContent = proto_decode_context(pRequest, nullptr, nullptr, &errCode); if (pStrContent == nullptr) { sprintf(logBuff, "Request Json error %s", pRequest); logDHCPMess(logBuff, 1); free((void *)pStrContent); return ERR_PROTO_DECODE; } #ifdef JSON_SCHEMA_ON if (errCode == ERR_JSON_VALID_SCH) { *pRsp = pStrContent; return ERR_SUCCESS; } const char *pSchJson; for(auto i : g_add_msg) { pSchJson = proto_msg_validation(pStrContent, i.pSchJson, i.pErrMsg); if (pSchJson != nullptr && strlen(pSchJson) > 0) { *pRsp = pSchJson; free((void *)pStrContent); return ERR_SUCCESS; } } free((void *)pSchJson); #endif cJSON *pRoot = cJSON_Parse(pStrContent); free((void *)pStrContent); if (!pRoot) { return ERR_JSON_PARSE_OBJ; } cJSON *prange_set = cJSON_GetObjectItem(pRoot, "rangeSet"); pRspRoot = cJSON_CreateObject(); pExpandArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspRoot, "rangeSet", pExpandArray); for (int i = 0; i < cJSON_GetArraySize(prange_set); i++) { int ret; cJSON *pItem = cJSON_GetArrayItem(prange_set, i); cJSON *pdhcp_range = cJSON_GetObjectItem(pItem, "dhcpRange"); cJSON *pEx_range = cJSON_CreateObject(); if (!pdhcp_range) { continue; } cJSON_AddStringToObject(pEx_range, "dhcpRange", pdhcp_range->valuestring); cJSON *psubnet_mask = cJSON_GetObjectItem(pItem, "netmask"); cJSON *pdomain_server = cJSON_GetObjectItem(pItem, "domainServer"); cJSON *pgateway = cJSON_GetObjectItem(pItem, "gateway"); cJSON *please_time = cJSON_GetObjectItem(pItem, "leaseTime"); memset(&range, 0, sizeof(OBJ_DHCP_RNG)); strcpy(range.rangAddr, pdhcp_range->valuestring); if (psubnet_mask) { strcpy(range.subnet, psubnet_mask->valuestring); } if (pdomain_server) { strcpy(range.dnsSvr, pdomain_server->valuestring); } if (pgateway) { strcpy(range.gateway, pgateway->valuestring); } if (please_time) { range.lease = please_time->valueint; } //写入cfig ret = dhcp_add_rangeset_to_options(&range); if (ret != ERR_SUCCESS) { cJSON_AddNumberToObject(pEx_range, "status", ret); cJSON_AddStringToObject(pEx_range, "message", getErrorEnumDesc(ret)); cJSON_AddItemToArray(pExpandArray, pEx_range); continue; } cJSON_AddNumberToObject(pEx_range, "status", ERR_SUCCESS); cJSON_AddStringToObject(pEx_range, "message", getErrorEnumDesc(ERR_SUCCESS)); cJSON_AddItemToArray(pExpandArray, pEx_range); } *pRsp = proto_create_new(pRspRoot, 200); cJSON_Delete(pRoot); return ERR_SUCCESS; } typedef struct { unsigned int key; unsigned int value; UT_hash_handle hh; } HASH_MAP, *PHASH_MAP; static int delete_dhcpd_rangeset(const char **pRsp, const char *pRequest) { char logBuff[512]; const char *pStrContent; char *fp; cJSON *pRspRoot; cJSON *pdelArray; data13 dhcpRanges[MAX_DHCP_RANGES]; PHASH_MAP delMap = nullptr; int resCount = 0; int errCode = 0; if (pRequest == nullptr || strlen(pRequest) == 0) { sprintf(logBuff, "Request Json"); logDHCPMess(logBuff, 1); return ERR_INPUT_PARAMS; } pStrContent = proto_decode_context(pRequest, nullptr, nullptr, &errCode); if (pStrContent == nullptr) { sprintf(logBuff, "Request Json error %s", pRequest); logDHCPMess(logBuff, 1); free((void*)pStrContent); return ERR_PROTO_DECODE; } #ifdef JSON_SCHEMA_ON if (errCode == ERR_JSON_VALID_SCH) { *pRsp = pStrContent; return ERR_SUCCESS; } const char *pSchJson; for(auto i : g_del_msg) { pSchJson = proto_msg_validation(pStrContent, i.pSchJson, i.pErrMsg); if (pSchJson != nullptr && strlen(pSchJson) > 0) { *pRsp = pSchJson; free((void*)pStrContent); return ERR_SUCCESS; } } free((void*)pSchJson); #endif cJSON *pRoot = cJSON_Parse(pStrContent); free((void *)pStrContent); if (!pRoot) { return ERR_JSON_PARSE_OBJ; } cJSON *pdhcp_range = cJSON_GetObjectItem(pRoot, "dhcpRange"); pRspRoot = cJSON_CreateObject(); pdelArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspRoot, "rangeSet", pdelArray); char start[128]; char end[128]; char del_range[256]; for (int i = 0; i < cJSON_GetArraySize(pdhcp_range); i++) { cJSON *pdelRange = cJSON_GetArrayItem(pdhcp_range, i); if (!pdelRange) { continue; } strcpy(del_range, pdelRange->valuestring); MYDWORD st_addr; MYDWORD en_addr; mySplit(start, end, del_range, '-'); if(isIP(start) && isIP(end)) { st_addr = htonl(inet_addr(start)); en_addr = htonl(inet_addr(end)); PHASH_MAP s; HASH_FIND_INT(delMap, &st_addr, s); if (s == nullptr) { s = (PHASH_MAP)malloc(sizeof(HASH_MAP)); s->key = st_addr; s->value = en_addr; HASH_ADD_INT(delMap, key, s); } } else { cJSON *pdel_Item = cJSON_CreateObject(); cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); cJSON_AddNumberToObject(pdel_Item, "status", ERR_INPUT_PARAMS); cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_INPUT_PARAMS)); cJSON_AddItemToArray(pdelArray, pdel_Item); } } for (int i = 0; i < cfig.rangeCount; i++) { cJSON *pdel_Item = cJSON_CreateObject(); PHASH_MAP delRange; memset(del_range, 0, 256); HASH_FIND_INT(delMap, &cfig.dhcpRanges[i].rangeStart, delRange); if (delRange != nullptr) { IP2String(start, ntohl(delRange->key)); IP2String(end, ntohl(delRange->value)); sprintf(del_range, "%s-%s", start, end); cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); //Determine whether the input is correct or not if (delRange->value == cfig.dhcpRanges[i].rangeEnd) { cJSON_AddNumberToObject(pdel_Item, "status", ERR_SUCCESS); cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_SUCCESS)); cJSON_AddItemToArray(pdelArray, pdel_Item); free(cfig.dhcpRanges[i].options); free(cfig.dhcpRanges[i].expiry); free(cfig.dhcpRanges[i].dhcpEntry); } else { memcpy(&dhcpRanges[resCount], &cfig.dhcpRanges[i], sizeof(struct data13)); resCount++; cJSON_AddNumberToObject(pdel_Item, "status", ERR_INPUT_PARAMS); cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_INPUT_PARAMS)); cJSON_AddItemToArray(pdelArray, pdel_Item); } HASH_DEL(delMap, delRange); free(delRange); } else { memcpy(&dhcpRanges[resCount], &cfig.dhcpRanges[i], sizeof(struct data13)); resCount++; cJSON_Delete(pdel_Item); } } //The input parameter does not exist PHASH_MAP s; PHASH_MAP tmp; memset(del_range, 0, 256); HASH_ITER(hh, delMap, s, tmp) HASH_ITER(hh, delMap, s, tmp) { cJSON *pdel_Item = cJSON_CreateObject(); IP2String(start, ntohl(s->key)); IP2String(end, ntohl(s->value)); sprintf(del_range, "%s-%s", start, end); cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); cJSON_AddNumberToObject(pdel_Item, "status", ERR_ITEM_UNEXISTS); cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_ITEM_UNEXISTS)); cJSON_AddItemToArray(pdelArray, pdel_Item); HASH_DEL(delMap, s); free(s); } //Rewrite cfig.dhcpRanges for (int i = 0; i < cfig.rangeCount; i++) { if (i < resCount) { memcpy(&cfig.dhcpRanges[i], &dhcpRanges[i], sizeof(struct data13)); } else { memset(&cfig.dhcpRanges[i], 0, sizeof(struct data13)); } } cfig.rangeCount = (char)resCount; *pRsp = proto_create_new(pRspRoot, 200); cJSON_Delete(pRoot); return ERR_SUCCESS; } static int query_dhcpd_rangeset(const char **pRsp) { char logBuff[512]; cJSON *pRspMsg = cJSON_CreateObject(); cJSON *pMsgArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspMsg, "rangeSet", pMsgArray); for (char rangeInd = 0; rangeInd < cfig.rangeCount; rangeInd++) { char addrStart[64]; char addrEnd[64]; char rangeSet[128]; char rangeMask[128]; char domainServer[128]; char gateway[128]; cJSON *pRangeItem = cJSON_CreateObject(); unsigned int lease; memset(domainServer, 0, 128); IP2String(addrStart, ntohl(cfig.dhcpRanges[rangeInd].rangeStart)); IP2String(addrEnd, ntohl(cfig.dhcpRanges[rangeInd].rangeEnd)); IP2String(rangeMask, cfig.dhcpRanges[rangeInd].mask); sprintf(rangeSet, "%s-%s", addrStart, addrEnd); cJSON_AddStringToObject(pRangeItem, "dhcpRange", rangeSet); cJSON_AddStringToObject(pRangeItem, "netmask", rangeMask); MYBYTE *opPointer = cfig.dhcpRanges[rangeInd].options; data3 op {}; if (opPointer) { opPointer++; while (*opPointer && *opPointer != DHCP_OPTION_END) { unsigned int tmpVal = 0; unsigned char dnsSize; unsigned char offset = 0; char dns_op[64]; op.opt_code = *opPointer; opPointer++; op.size = *opPointer; opPointer++; memcpy(op.value, opPointer, op.size); if (op.opt_code == DHCP_OPTION_DNS) { dnsSize = op.size; do { tmpVal = fIP(op.value + offset); IP2String(dns_op, htonl(ntohl(tmpVal))); sprintf(domainServer, "%s%s", domainServer, dns_op); if (dnsSize != 4) { sprintf(domainServer, "%s,", domainServer); } dnsSize -= 4; offset = op.size - dnsSize; } while (dnsSize != 0); cJSON_AddStringToObject(pRangeItem, "domainServer", domainServer); } else if (op.opt_code == DHCP_OPTION_ROUTER) { tmpVal = fIP(op.value); IP2String(gateway, htonl(ntohl(tmpVal))); cJSON_AddStringToObject(pRangeItem, "gateway", gateway); } else if (op.opt_code == DHCP_OPTION_IPADDRLEASE) { lease = fUInt(op.value); cJSON_AddNumberToObject(pRangeItem, "leaseTime", lease); } opPointer += op.size; } } cJSON_AddItemToArray(pMsgArray, pRangeItem); } cJSON_AddNumberToObject(pRspMsg, "status", ERR_SUCCESS); cJSON_AddStringToObject(pRspMsg, "message", getErrorEnumDesc(ERR_SUCCESS)); *pRsp = proto_create_new(pRspMsg, 200); return ERR_SUCCESS; } #pragma clang diagnostic push #pragma ide diagnostic ignored "cert-err34-c" int getHwAddr(char *buff, char *mac) { if (buff == nullptr || mac == nullptr) { return -1; } int i; unsigned int p[6]; if (sscanf(mac, "%x:%x:%x:%x:%x:%x", &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]) < 6) { return -1; } for (i = 0; i < 6; i++) { buff[i] = (char)p[i]; } return 0; } #pragma clang diagnostic pop #if DISCOVER_RSP_NOT_BOARDCAST int arpSet(const char *ifname, char *ipStr, char *mac) { if (ifname == nullptr || ipStr == nullptr || mac == nullptr) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "para is null.\n"); return -1; } struct arpreq req {}; struct sockaddr_in *sin; int ret; int sock_fd; memset(&req, 0, sizeof(struct arpreq)); sin = (struct sockaddr_in *)&req.arp_pa; sin->sin_family = AF_INET; sin->sin_addr.s_addr = inet_addr(ipStr); //arp_dev长度为[16],注意越界 strncpy(req.arp_dev, ifname, 15); req.arp_flags = ATF_PERM | ATF_COM; if (getHwAddr((char *)req.arp_ha.sa_data, mac) < 0) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "get mac error.\n"); return -1; } sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "get socket error.\n"); return -1; } ret = ioctl(sock_fd, SIOCSARP, &req); if (ret < 0) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "ioctl error.\n"); close(sock_fd); return -1; } close(sock_fd); return 0; } sockaddr_in get_cliAddr(char *nicif, char *tempbuff, data9 *req) { arpSet(nicif, IP2String(tempbuff, req->dhcpp.header.bp_yiaddr), req->chaddr); sockaddr_in cliAddr {}; memcpy(&cliAddr, &req->remote, sizeof(sockaddr_in)); cliAddr.sin_addr.s_addr = inet_addr(IP2String(tempbuff, req->dhcpp.header.bp_yiaddr)); return cliAddr; } #endif unsigned int opendhcp_set_lease_time() { return config_get_dhcp_server_lease_time(); } /** * 添加配置文件监听接口 * @return */ int opendhcp_add_listener() { int i; c_vector listen_ip = config_get_dhcp_listen_on(); for (i = 0; listen_ip && i < vect_size(listen_ip); i++) { const char *pIp = (const char *)vect_get_at(listen_ip, i); if (pIp && strlen(pIp) > 0) { MYDWORD addr = inet_addr(pIp); addServer(cfig.specifiedServers, MAX_SERVERS, addr); } } return i; } static void on_http_response_cb(void *pData, unsigned int size, const char *pReqUrl, const char *pDlPath, const char *pTaskUuid, int iFinished, void *pUserData) { if (iFinished == 0) { LOG_MOD(debug, ZLOG_MOD_OPENDHCPD, "Request(%s): [%s] Response: [%u] OK:\n", pTaskUuid, pReqUrl, size); } else if (iFinished == 1) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "Request(%s): [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, size); } else { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "Download Error Code: %d\n", iFinished); } free(pUserData); } void iptvCacheCb(uv_timer_t *UNUSED(pArg)) { bool isReport = false; const char *pUrl = config_get_agent_iptv_report_url(); PIPTV_DEV_SET report = nullptr; PIPTV_DEV_SET pDev, pTmp = nullptr; uv_rwlock_wrlock(&g_uvCacheLock); HASH_ITER(hh, g_iptvNewDevs, pDev, pTmp) uv_sleep(10); HASH_ITER(hh, report, pDev, pTmp) { HASH_DEL(report, pDev); free(pDev); } HASH_ITER(hh, report, pDev, pTmp) if (isReport && pUrl && strlen(pUrl) > 0) { cJSON *pRspMsg = cJSON_CreateObject(); cJSON *pMsgArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspMsg, "iptvDevs", pMsgArray); HASH_ITER(hh, report, pDev, pTmp) { cJSON *pRspItem = cJSON_CreateObject(); cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); pDev->isReport = 1; cJSON_AddItemToArray(pMsgArray, pRspItem); } const char *pStrPro = proto_create_new(pRspMsg, 200); // Report new IPTV device MAC inet_http_post_async(pUrl, pStrPro, on_http_response_cb, (void *)pStrPro); } uv_rwlock_wrunlock(&g_uvCacheLock); HASH_ITER(hh, g_iptvNewDevs, pDev, pTmp) { PIPTV_DEV_SET pTemp; const char *pDevMac = strdup(pDev->iptvMAC); HASH_FIND_STR(g_iptvCacheDevs, pDevMac, pTemp); // 新发现设备没有被上报过 if (!pTemp) { auto pCacheDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); auto pRepDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); memcpy(pCacheDev, pDev, sizeof(IPTV_DEV_SET)); memcpy(pRepDev, pDev, sizeof(IPTV_DEV_SET)); HASH_ADD_STR(report, iptvMAC, pRepDev); isReport = true; // 添加到缓存列表供后续查询 HASH_ADD_STR(g_iptvCacheDevs, iptvMAC, pCacheDev); LOG_MOD(debug, ZLOG_MOD_OPENDHCPD, "Add IPTV device %s vni %d to cache\n", pCacheDev->iptvMAC, pCacheDev->vni); } HASH_DEL(g_iptvNewDevs, pDev); free(pDev); free((void *)pDevMac); } } /** * 增加 DHCP Server HTTP服务接口 */ #ifdef HTTPSERVER_ON #define HTTP_HEAD_CONTENT_TYPE_JSON "Content-Type: application/json\r\n" #define HTTP_HEAD_CONTENT_TYPE_HTML "Content-Type: text/html\r\n" static void on_get_userinfo(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_JSON; pCtx->errCode = dhcp_get_user_info((const char **)&pCtx->pRspData, h->body.ptr); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } static void on_del_rangeset(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_JSON; pCtx->errCode = delete_dhcpd_rangeset((const char **)&pCtx->pRspData, h->body.ptr); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } static void on_add_rangeset(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_JSON; pCtx->errCode = add_dhcpd_rangeset((const char **)&pCtx->pRspData, h->body.ptr); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } static void on_get_rangeset(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_JSON; pCtx->errCode = query_dhcpd_rangeset((const char **)&pCtx->pRspData); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } static void on_get_iptv_devs(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_JSON; pCtx->errCode = dchp_get_all_iptv_devs((const char **)&pCtx->pRspData); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } static void on_dhcpd_info(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_HTML; pCtx->errCode = prepareUserHtmlRespStatus((const char **)&pCtx->pRspData); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } static void on_get_alluser(struct mg_http_message *h, void *user_data, PHTTP_RSP_CTX pCtx) { pCtx->pRspHeads = HTTP_HEAD_CONTENT_TYPE_JSON; pCtx->errCode = dhcp_get_all_user((const char **)&pCtx->pRspData); if (pCtx->errCode != ERR_SUCCESS) { pCtx->httpCode = 500; free(pCtx->pRspData); return; } pCtx->httpCode = 200; } typedef struct HTTP_ROUTE_INFO { char routeName[MAX_URI]; HTTP_METHOD method; HTTP_ROUTE_PRIORITY priority; HTTP_REQUEST_CB cb; void *pUserData; } HTTP_ROUTE_INFO, *PHTTP_ROUTE_INFO; static HTTP_ROUTE_INFO g_routeTable[] = { {"/", GET, PRI_LOWEASE, on_dhcpd_info, nullptr}, {"/dhcp/info/getuser", POST, PRI_NORMAL, on_get_userinfo, nullptr}, {"/dhcp/info/allusers", GET, PRI_NORMAL, on_get_alluser, nullptr}, {"/dhcp/config/rangeset", POST, PRI_NORMAL, on_add_rangeset, nullptr}, {"/dhcp/delete/rangeset", POST, PRI_NORMAL, on_del_rangeset, nullptr}, {"/dhcp/query/rangeset", GET, PRI_NORMAL, on_get_rangeset, nullptr}, {"/dhcp/query/iptvdevice", GET, PRI_NORMAL, on_get_iptv_devs, nullptr}, }; void opendhcp_init_http_server() { static int added = FALSE; static uv_timer_t uvTm; if (!added) { uv_rwlock_init(&g_uvCacheLock); uv_timer_init(get_task_manager(), &uvTm); uv_timer_start(&uvTm, iptvCacheCb, 1000, 1000); for (auto &i : g_routeTable) { PHTTP_ROUTE_INFO p = &i; http_add_route(p->routeName, p->method, p->priority, p->cb, p->pUserData); } added = TRUE; #ifdef USERVNI_ON LOG_MOD(info, ZLOG_MOD_OPENDHCPD, "User VxLan Id: [%d]\n", cfg_get_user_vni_id()); #endif } } #endif /** * 增加 DHCP 主、从服务器配置 */ void opendhcp_set_replication_svr() { c_vector replication = config_get_dhcp_replication_svr(); if (replication && vect_size(replication) == 2) { cfig.zoneServers[0] = inet_addr((const char *)vect_get_at(replication, 0)); cfig.zoneServers[1] = inet_addr((const char *)vect_get_at(replication, 1)); } } /** * 添加配置文件中的 DHCP 地址池池配置到服务中 */ void opendhcp_add_ip_pool_set() { c_vector pool = config_get_dhcp_server_range_set(); for (int i = 0; (pool && i < vect_size(pool)); i++) { auto pRange = (POBJ_DHCP_RNG)vect_get_at(pool, i); if (pRange) { if (dhcp_add_rangeset_to_options(pRange) != ERR_SUCCESS) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "Add rangeset(\"%s\") failed!\n", pRange->rangAddr); } } } } int process_iptv_multicast(const unsigned char *p, int size, const char *mac) { char ipTvId[16] = {0}; memcpy(ipTvId, &p[4], 10); if (strcmp(ipTvId, "JSCMCC-OTT") == 0) { PIPTV_DEV_SET pTmp; HASH_FIND_STR(g_iptvNewDevs, mac, pTmp); if (!pTmp) { auto pDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); if (pDev) { memset(pDev, 0, sizeof(IPTV_DEV_SET)); strcpy(pDev->iptvMAC, mac); #ifdef USERVNI_ON pDev->vni = cfg_get_user_vni_id(); #else pDev->vni = 0; #endif pDev->isReport = 0; uv_rwlock_wrlock(&g_uvCacheLock); HASH_ADD_STR(g_iptvNewDevs, iptvMAC, pDev); uv_rwlock_wrunlock(&g_uvCacheLock); } } LOG_MOD(debug, ZLOG_MOD_OPENDHCPD, "Found IPTV %s\n", mac); return 0; } return 1; } /** * 增加MAC地址黑名单 */ void opendhcp_add_mac_filter() { c_vector pool = config_get_dhcp_mac_filter(); data20 optionData {}; optionData.options[0] = 0; optionData.options[1] = DHCP_OPTION_END; sds add = sdsempty(); sds err = sdsempty(); for (int i = 0; (pool && i < vect_size(pool)); i++) { auto pRange = (char *)vect_get_at(pool, i); if (pRange) { data7 *dhcpEntry; memset(&lump, 0, sizeof(data71)); lump.mapname = pRange; lump.optionSize = 2; lump.options = optionData.options; dhcpEntry = createCache(&lump); if (dhcpEntry) { dhcpEntry->ip = 0; dhcpEntry->rangeInd = -1; dhcpEntry->fixed = 1; dhcpEntry->expiry = 0; dhcpCache[dhcpEntry->mapname] = dhcpEntry; add = sdscatfmt(add, "\"%s\", ", pRange); } else { err = sdscatfmt(err, "\"%s\", ", pRange); } } } if (sdslen(add) > 0) { sdsrange(add, 0, -3); LOG_MOD(debug, ZLOG_MOD_OPENDHCPD, "Add MAC [%s] for black list\n", add); } if (sdslen(err) > 0) { sdsrange(err, 0, -2); LOG_MOD(debug, ZLOG_MOD_OPENDHCPD, "Add MAC [%s] for black list error\n", err); } sdsfree(add); sdsfree(err); }