parse_varlen.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /* Copyright (c) 2016 Facebook
  2. *
  3. * This program is free software; you can redistribute it and/or
  4. * modify it under the terms of version 2 of the GNU General Public
  5. * License as published by the Free Software Foundation.
  6. */
  7. #include <linux/if_ether.h>
  8. #include <linux/ip.h>
  9. #include <linux/ipv6.h>
  10. #include <linux/in.h>
  11. #include <linux/tcp.h>
  12. #include <linux/udp.h>
  13. #include <uapi/linux/bpf.h>
  14. #include <net/ip.h>
  15. #include "bpf_helpers.h"
  16. #define DEFAULT_PKTGEN_UDP_PORT 9
  17. #define DEBUG 0
  18. static int tcp(void *data, uint64_t tp_off, void *data_end)
  19. {
  20. struct tcphdr *tcp = data + tp_off;
  21. if (tcp + 1 > data_end)
  22. return 0;
  23. if (tcp->dest == htons(80) || tcp->source == htons(80))
  24. return TC_ACT_SHOT;
  25. return 0;
  26. }
  27. static int udp(void *data, uint64_t tp_off, void *data_end)
  28. {
  29. struct udphdr *udp = data + tp_off;
  30. if (udp + 1 > data_end)
  31. return 0;
  32. if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT) ||
  33. udp->source == htons(DEFAULT_PKTGEN_UDP_PORT)) {
  34. if (DEBUG) {
  35. char fmt[] = "udp port 9 indeed\n";
  36. bpf_trace_printk(fmt, sizeof(fmt));
  37. }
  38. return TC_ACT_SHOT;
  39. }
  40. return 0;
  41. }
  42. static int parse_ipv4(void *data, uint64_t nh_off, void *data_end)
  43. {
  44. struct iphdr *iph;
  45. uint64_t ihl_len;
  46. iph = data + nh_off;
  47. if (iph + 1 > data_end)
  48. return 0;
  49. if (ip_is_fragment(iph))
  50. return 0;
  51. ihl_len = iph->ihl * 4;
  52. if (iph->protocol == IPPROTO_IPIP) {
  53. iph = data + nh_off + ihl_len;
  54. if (iph + 1 > data_end)
  55. return 0;
  56. ihl_len += iph->ihl * 4;
  57. }
  58. if (iph->protocol == IPPROTO_TCP)
  59. return tcp(data, nh_off + ihl_len, data_end);
  60. else if (iph->protocol == IPPROTO_UDP)
  61. return udp(data, nh_off + ihl_len, data_end);
  62. return 0;
  63. }
  64. static int parse_ipv6(void *data, uint64_t nh_off, void *data_end)
  65. {
  66. struct ipv6hdr *ip6h;
  67. struct iphdr *iph;
  68. uint64_t ihl_len = sizeof(struct ipv6hdr);
  69. uint64_t nexthdr;
  70. ip6h = data + nh_off;
  71. if (ip6h + 1 > data_end)
  72. return 0;
  73. nexthdr = ip6h->nexthdr;
  74. if (nexthdr == IPPROTO_IPIP) {
  75. iph = data + nh_off + ihl_len;
  76. if (iph + 1 > data_end)
  77. return 0;
  78. ihl_len += iph->ihl * 4;
  79. nexthdr = iph->protocol;
  80. } else if (nexthdr == IPPROTO_IPV6) {
  81. ip6h = data + nh_off + ihl_len;
  82. if (ip6h + 1 > data_end)
  83. return 0;
  84. ihl_len += sizeof(struct ipv6hdr);
  85. nexthdr = ip6h->nexthdr;
  86. }
  87. if (nexthdr == IPPROTO_TCP)
  88. return tcp(data, nh_off + ihl_len, data_end);
  89. else if (nexthdr == IPPROTO_UDP)
  90. return udp(data, nh_off + ihl_len, data_end);
  91. return 0;
  92. }
  93. struct vlan_hdr {
  94. uint16_t h_vlan_TCI;
  95. uint16_t h_vlan_encapsulated_proto;
  96. };
  97. SEC("varlen")
  98. int handle_ingress(struct __sk_buff *skb)
  99. {
  100. void *data = (void *)(long)skb->data;
  101. struct ethhdr *eth = data;
  102. void *data_end = (void *)(long)skb->data_end;
  103. uint64_t h_proto, nh_off;
  104. nh_off = sizeof(*eth);
  105. if (data + nh_off > data_end)
  106. return 0;
  107. h_proto = eth->h_proto;
  108. if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
  109. struct vlan_hdr *vhdr;
  110. vhdr = data + nh_off;
  111. nh_off += sizeof(struct vlan_hdr);
  112. if (data + nh_off > data_end)
  113. return 0;
  114. h_proto = vhdr->h_vlan_encapsulated_proto;
  115. }
  116. if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
  117. struct vlan_hdr *vhdr;
  118. vhdr = data + nh_off;
  119. nh_off += sizeof(struct vlan_hdr);
  120. if (data + nh_off > data_end)
  121. return 0;
  122. h_proto = vhdr->h_vlan_encapsulated_proto;
  123. }
  124. if (h_proto == htons(ETH_P_IP))
  125. return parse_ipv4(data, nh_off, data_end);
  126. else if (h_proto == htons(ETH_P_IPV6))
  127. return parse_ipv6(data, nh_off, data_end);
  128. return 0;
  129. }
  130. char _license[] SEC("license") = "GPL";