luat_netdrv_napt_icmp.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include "luat_base.h"
  2. #include "luat_netdrv.h"
  3. #include "luat_network_adapter.h"
  4. #include "luat_netdrv_ch390h.h"
  5. #include "luat_malloc.h"
  6. #include "luat_netdrv_napt.h"
  7. #include "lwip/pbuf.h"
  8. #include "lwip/ip.h"
  9. #include "lwip/etharp.h"
  10. #include "lwip/icmp.h"
  11. #include "luat_mcu.h"
  12. #define LUAT_LOG_TAG "netdrv.napt.icmp"
  13. #include "luat_log.h"
  14. #define ICMP_MAP_SIZE (64)
  15. #define ICMP_MAP_TIMEOUT (5000)
  16. /* napt icmp id range: 3000-65535 */
  17. #define NAPT_ICMP_ID_RANGE_START 0x1BB8
  18. #define NAPT_ICMP_ID_RANGE_END 0xFFFF
  19. extern int luat_netdrv_gw_adapter_id;
  20. static uint16_t napt_curr_id = NAPT_ICMP_ID_RANGE_START;
  21. static luat_netdrv_napt_icmp_t icmps[ICMP_MAP_SIZE];
  22. #define u32 uint32_t
  23. #define u16 uint16_t
  24. #define u8 uint8_t
  25. #define NAPT_ETH_HDR_LEN sizeof(struct ethhdr)
  26. static u16 luat_napt_icmp_id_alloc(void)
  27. {
  28. u16 cnt = 0;
  29. again:
  30. if (napt_curr_id++ == NAPT_ICMP_ID_RANGE_END)
  31. {
  32. napt_curr_id = NAPT_ICMP_ID_RANGE_START;
  33. }
  34. for (size_t i = 0; i < ICMP_MAP_SIZE; i++)
  35. {
  36. if (napt_curr_id == icmps[i].wnet_id)
  37. {
  38. if (++cnt > (NAPT_ICMP_ID_RANGE_END - NAPT_ICMP_ID_RANGE_START))
  39. {
  40. return 0;
  41. }
  42. goto again;
  43. }
  44. }
  45. return napt_curr_id;
  46. }
  47. static uint8_t icmp_buff[1600];
  48. int luat_napt_icmp_handle(napt_ctx_t* ctx) {
  49. uint16_t iphdr_len = (ctx->iphdr->_v_hl & 0x0F) * 4;
  50. struct ip_hdr* ip_hdr = ctx->iphdr;
  51. struct icmp_echo_hdr *icmp_hdr = (struct icmp_echo_hdr*)(((uint8_t*)ctx->iphdr) + iphdr_len);
  52. luat_netdrv_t* gw = luat_netdrv_get(luat_netdrv_gw_adapter_id);
  53. if (gw == NULL || gw->netif == NULL) {
  54. return 0;
  55. }
  56. if (ctx->is_wnet) {
  57. // 这是从外网到内网的PONG
  58. for (size_t i = 0; i < ICMP_MAP_SIZE; i++)
  59. {
  60. if (icmps[i].is_vaild == 0) {
  61. continue;
  62. }
  63. if (icmp_hdr->id != icmps[i].wnet_id) {
  64. continue;
  65. }
  66. if (ip_hdr->src.addr != icmps[i].wnet_ip) {
  67. continue;
  68. }
  69. // 找到映射关系了!!!
  70. LLOGD("ICMP id %u -> %d", icmp_hdr->id, icmps[i].inet_id);
  71. // 修改目标ID
  72. icmp_hdr->id = icmps[i].inet_id;
  73. // 重新计算icmp的checksum
  74. icmp_hdr->chksum = 0;
  75. icmp_hdr->chksum = alg_iphdr_chksum((u16 *)icmp_hdr, ntohs(ip_hdr->_len) - iphdr_len);
  76. // 修改目标地址,并重新计算ip的checksu
  77. ip_hdr->dest.addr = icmps[i].inet_ip;
  78. ip_hdr->_chksum = 0;
  79. ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
  80. // 如果是ETH包, 那还需要修改源MAC和目标MAC
  81. if (ctx->eth) {
  82. memcpy(ctx->eth->src.addr, ctx->net->netif->hwaddr, 6);
  83. memcpy(ctx->eth->dest.addr, icmps[i].inet_mac, 6);
  84. }
  85. luat_netdrv_t* dst = luat_netdrv_get(icmps[i].adapter_id);
  86. if (dst == NULL) {
  87. LLOGE("能找到ICMP映射关系, 但目标netdrv不存在, 这肯定是BUG啊!!");
  88. return 1;
  89. }
  90. if (dst->dataout) {
  91. if (ctx->eth && dst->netif->flags & NETIF_FLAG_ETHARP) {
  92. LLOGD("输出到内网netdrv,无需额外添加eth头");
  93. dst->dataout(dst->userdata, icmp_buff, ctx->len);
  94. }
  95. else if (!ctx->eth && dst->netif->flags & NETIF_FLAG_ETHARP) {
  96. // 需要补全一个ETH头部
  97. memcpy(icmp_buff, icmps[i].inet_mac, 6);
  98. memcpy(icmp_buff + 6, dst->netif->hwaddr, 6);
  99. memcpy(icmp_buff + 12, "\x08\x00", 2);
  100. memcpy(icmp_buff + 14, ip_hdr, ctx->len);
  101. dst->dataout(dst->userdata, icmp_buff, ctx->len + 14);
  102. // LLOGD("输出到内网netdrv,已额外添加eth头");
  103. // luat_netdrv_print_pkg("下行数据", icmp_buff, ctx->len + 14);
  104. }
  105. }
  106. else {
  107. LLOGE("能找到ICMP映射关系, 但目标netdrv不支持dataout!!");
  108. }
  109. icmps[i].is_vaild = 0;
  110. return 1; // 全部修改完成
  111. }
  112. // LLOGD("没有找到ICMP映射关系, 不是非内网PING");
  113. return 0;
  114. }
  115. else {
  116. // 内网, 尝试对外网的请求吗?
  117. if (ip_hdr->dest.addr == ip_addr_get_ip4_u32(&ctx->net->netif->ip_addr)) {
  118. return 0; // 对网关的ICMP/PING请求, 交给LWIP处理
  119. }
  120. // 寻找一个空位
  121. uint64_t tnow = luat_mcu_tick64_ms();
  122. for (size_t i = 0; i < ICMP_MAP_SIZE; i++)
  123. {
  124. if (icmps[i].is_vaild && (tnow - icmps[i].tm_ms) < ICMP_MAP_TIMEOUT) {
  125. continue;
  126. }
  127. if (icmps[i].is_vaild && (tnow - icmps[i].tm_ms) > ICMP_MAP_TIMEOUT) {
  128. icmps[i].is_vaild = 0;
  129. }
  130. // 有空位, 马上处理
  131. // 1. 保存信息
  132. icmps[i].adapter_id = ctx->net->id;
  133. icmps[i].inet_id = icmp_hdr->id;
  134. icmps[i].inet_ip = ip_hdr->src.addr;
  135. icmps[i].wnet_id = luat_napt_icmp_id_alloc();
  136. icmps[i].wnet_ip = ip_hdr->dest.addr;
  137. // 2. 修改信息
  138. ip_hdr->src.addr = ip_addr_get_ip4_u32(&gw->netif->ip_addr);
  139. icmp_hdr->id = icmps[i].wnet_id;
  140. // 3. 重新计算checksum
  141. icmp_hdr->chksum = 0;
  142. icmp_hdr->chksum = alg_iphdr_chksum((u16 *)icmp_hdr, ntohs(ip_hdr->_len) - iphdr_len);
  143. // 4. 计算IP包的checksum
  144. ip_hdr->_chksum = 0;
  145. ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
  146. // 5. 如果是ETH包, 还得修正MAC地址
  147. if (ctx->eth) {
  148. memcpy(icmps[i].inet_mac, ctx->eth->src.addr, 6);
  149. }
  150. icmps[i].is_vaild = 1;
  151. if (gw && gw->dataout && gw->netif) {
  152. // LLOGD("ICMP改写完成, 发送到GW");
  153. if (gw->netif->flags & NETIF_FLAG_ETHARP) {
  154. // TODO 网关设备也是ETHARP? 还不支持
  155. LLOGD("网关netdrv也是ETH, 当前不支持");
  156. }
  157. else {
  158. if (ctx->eth) {
  159. gw->dataout(gw->userdata, ip_hdr, ctx->len - 14);
  160. }
  161. else {
  162. gw->dataout(gw->userdata, ip_hdr, ctx->len);
  163. }
  164. }
  165. }
  166. else {
  167. LLOGD("ICMP改写完成, 但GW不支持dataout回调?!!");
  168. }
  169. return 1;
  170. }
  171. LLOGD("没有ICMP空位了");
  172. }
  173. return 0;
  174. }