{"action":"created","comment":{"url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments/89261570","pull_request_review_id":9807930,"id":89261570,"diff_hunk":"@@ -16,11 +16,401 @@\n  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n  */\n \n+#include <stdbool.h>\n+\n+#include <rte_ip.h>\n+#include <rte_udp.h>\n+#include <rte_log.h>\n+#include <rte_lcore.h>\n+#include <rte_malloc.h>\n+#include <rte_ethdev.h>\n+#include <rte_atomic.h>\n+\n+#include \"gatekeeper_gk.h\"\n #include \"gatekeeper_ggu.h\"\n+#include \"gatekeeper_net.h\"\n+#include \"gatekeeper_main.h\"\n+#include \"gatekeeper_config.h\"\n+\n+#define GGU_PD_VER1 (1)\n+\n+static void\n+process_single_policy(struct ggu_policy *policy, struct ggu_config *ggu_conf)\n+{\n+\tint ret;\n+\tstruct gk_cmd_entry *entry = NULL;\n+\t/*\n+\t * Obtain mailbox of that GK block,\n+\t * and send the policy decision to the GK block.\n+\t */\n+\tstruct mailbox *mb =\n+\t\tget_responsible_gk_mailbox(&policy->flow, ggu_conf->gk);\n+\n+\tif (mb == NULL)\n+\t\treturn;\n+\n+\tret = mb_get_entry(mb, (void **)&entry);\n+\tif (ret < 0)\n+\t\treturn;\n+\n+\tentry->op = GGU_POLICY_ADD;\n+\tentry->u.ggu.state = policy->state;\n+\trte_memcpy(&entry->u.ggu.flow, &policy->flow, sizeof(entry->u.ggu.flow));\n+\n+\tswitch(policy->state) {\n+\tcase GK_GRANTED:\n+\t\tentry->u.ggu.params.u.granted.tx_rate_kb_sec =\n+\t\t\trte_be_to_cpu_32(\n+\t\t\tpolicy->params.u.granted.tx_rate_kb_sec);\n+\t\tentry->u.ggu.params.u.granted.cap_expire_sec =\n+\t\t\trte_be_to_cpu_32(\n+\t\t\tpolicy->params.u.granted.cap_expire_sec);\n+\t\tentry->u.ggu.params.u.granted.next_renewal_ms =\n+\t\t\trte_be_to_cpu_32(\n+\t\t\tpolicy->params.u.granted.next_renewal_ms);\n+\t\tentry->u.ggu.params.u.granted.renewal_step_ms =\n+\t\t\trte_be_to_cpu_32(\n+\t\t\tpolicy->params.u.granted.renewal_step_ms);\n+\t\tbreak;\n+\n+\tcase GK_DECLINED:\n+\t\tentry->u.ggu.params.u.declined.expire_sec =\n+\t\t\trte_be_to_cpu_32(policy->params.u.declined.expire_sec);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tRTE_LOG(ERR, GATEKEEPER, \"ggu: impossible policy state %hhu\\n\",\n+\t\t\tpolicy->state);\n+\t\tbreak;\n+\t}\n+\n+\tmb_put_entry(mb, entry);\n+}\n+\n+static int\n+validate_packet_len(struct rte_mbuf *pkt, uint16_t proto)\n+{\n+\tuint16_t minimum_size = sizeof(struct ether_hdr);\n+\n+\tif (proto == ETHER_TYPE_IPv4)\n+\t\tminimum_size += sizeof(struct ipv4_hdr);\n+\telse if (proto == ETHER_TYPE_IPv6)\n+\t\tminimum_size += sizeof(struct ipv6_hdr);\n+\telse {\n+\t\tRTE_LOG(NOTICE, GATEKEEPER,\n+\t\t\t\"ggu: unknown packet type %hu\\n\",\n+\t\t\tproto);\n+\t\treturn -1;\n+\t}\n+\n+\tminimum_size += sizeof(struct udp_hdr) + sizeof(struct ggu_common_hdr);\n+\n+\tif (pkt->data_len < minimum_size) {\n+\t\tRTE_LOG(NOTICE, GATEKEEPER,\n+\t\t\t\"ggu: the packet doesn't have the minimum expected size %hu\\n\",\n+\t\t\tminimum_size);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+process_single_packet(struct rte_mbuf *pkt, struct ggu_config *ggu_conf)\n+{\n+\tuint8_t j;\n+\tuint8_t *policy_ptr;\n+\tuint16_t ether_type;\n+\tstruct ether_hdr *eth_hdr;\n+\tstruct ipv4_hdr *ip4hdr;\n+\tstruct ipv6_hdr *ip6hdr;\n+\tstruct udp_hdr *udphdr;\n+\tstruct ggu_common_hdr *gguhdr;\n+\tuint16_t real_payload_len;\n+\tuint16_t expected_payload_len;\n+\tstruct ggu_policy policy;\n+\n+\teth_hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);\n+\tether_type = rte_be_to_cpu_16(eth_hdr->ether_type);\n+\n+\tswitch (ether_type) {\n+\tcase ETHER_TYPE_IPv4:\n+\t\tif (validate_packet_len(pkt, ETHER_TYPE_IPv4) < 0)\n+\t\t\tgoto free_packet;\n+\n+\t\tip4hdr = rte_pktmbuf_mtod_offset(pkt, \n+\t\t\tstruct ipv4_hdr *, sizeof(struct ether_hdr));\n+\t\tif (ip4hdr->next_proto_id != IPPROTO_UDP) {\n+\t\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\t\"ggu: received non-UDP packets, IPv4 ntuple filter bug!\\n\");\n+\t\t\tgoto free_packet;\n+\t\t}\n+\n+\t\tif (ip4hdr->dst_addr != ggu_conf->net->back.ip4_addr.s_addr) {\n+\t\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\t\"ggu: received packets not destined to the Gatekeeper server, IPv4 ntuple filter bug!\\n\");\n+\t\t\tgoto free_packet;\n+\t\t}\n+\n+\t\tudphdr = (struct udp_hdr *)&ip4hdr[1];\n+\t\tbreak;\n+\n+\tcase ETHER_TYPE_IPv6:\n+\t\tif (validate_packet_len(pkt, ETHER_TYPE_IPv6) < 0)\n+\t\t\tgoto free_packet;\n+\n+\t\tip6hdr = rte_pktmbuf_mtod_offset(pkt, \n+\t\t\tstruct ipv6_hdr *, sizeof(struct ether_hdr));\n+\t\tif (ip6hdr->proto != IPPROTO_UDP) {\n+\t\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\t\"ggu: received non-UDP packets, IPv6 ntuple filter bug!\\n\");\n+\t\t\tgoto free_packet;\n+\t\t}\n+\n+\t\t/*\n+\t\t * TODO Given that IPv6 ntuple filter doesn't check\n+\t\t * the destination address, it must be done here.\n+\t\t * If the IPv6 packet is not destined to\n+\t\t * the Gatekeeper server, redirect the packet properly.\n+\t\t */\n+\t\tif (memcmp(ip6hdr->dst_addr,\n+\t\t\t\tggu_conf->net->back.ip6_addr.s6_addr,\n+\t\t\t\tsizeof(ip6hdr->dst_addr)) != 0) {\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tudphdr = (struct udp_hdr *)&ip6hdr[1];\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tRTE_LOG(NOTICE, GATEKEEPER,\n+\t\t\t\"ggu: unknown network layer protocol %hu\\n\",\n+\t\t\tether_type);\n+\t\tgoto free_packet;\n+\t\tbreak;\n+\t}\n+\n+\t/* XXX Check the UDP checksum. */\n+\n+\tif (udphdr->src_port != ggu_conf->ggu_src_port ||\n+\t\t\tudphdr->dst_port != ggu_conf->ggu_dst_port) {\n+\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\"ggu: unknown udp src port %hu, dst port %hu, ntuple filter bug!\\n\",\n+\t\t\trte_be_to_cpu_16(udphdr->src_port),\n+\t\t\trte_be_to_cpu_16(udphdr->dst_port));\n+\t\tgoto free_packet;\n+\t}\n+\n+\tgguhdr = (struct ggu_common_hdr *)&udphdr[1];\n+\tif (gguhdr->v1 != GGU_PD_VER1) {\n+\t\tRTE_LOG(NOTICE, GATEKEEPER,\n+\t\t\t\"ggu: unknown policy decision format %hhu\\n\",\n+\t\t\tgguhdr->v1);\n+\t\tgoto free_packet;\n+\t}\n+\n+\tpolicy_ptr = (uint8_t *)&gguhdr[1];\n+\n+\treal_payload_len = rte_be_to_cpu_16(udphdr->dgram_len);\n+\texpected_payload_len = sizeof(*udphdr) + sizeof(*gguhdr) +\n+\t\t(gguhdr->n1 + gguhdr->n3) * sizeof(policy.flow.f.v4) +\n+\t\t(gguhdr->n2 + gguhdr->n4) * sizeof(policy.flow.f.v6) +\n+\t\t(gguhdr->n1 + gguhdr->n2) * sizeof(policy.params.u.declined) + \n+\t\t(gguhdr->n3 + gguhdr->n4) * sizeof(policy.params.u.granted);\n+\tif (real_payload_len < expected_payload_len) {\n+\t\tRTE_LOG(NOTICE, GATEKEEPER,\n+\t\t\t\"ggu: the size (%hu) of the payload available in the UDP header doesn't match the expected size (%hu)!\\n\",\n+\t\t\treal_payload_len, expected_payload_len);\n+\t\tgoto free_packet;\n+\t}\n+\n+\t/* Loop over each policy decision on the packet. */\n+\n+\t/* Process the IPv4 decline decisions. */\n+\tfor (j = 0; j < gguhdr->n1; j++) {\n+\t\tmemset(&policy, 0, sizeof(policy));\n+\t\tpolicy.state = GK_DECLINED;\n+\t\tpolicy.flow.proto = ETHER_TYPE_IPv4;\n+\t\trte_memcpy(&policy.flow.f.v4, policy_ptr,\n+\t\t\tsizeof(policy.flow.f.v4));\n+\t\tpolicy_ptr += sizeof(policy.flow.f.v4);\n+\t\trte_memcpy(&policy.params.u.declined, policy_ptr,\n+\t\t\tsizeof(policy.params.u.declined));\n+\t\tpolicy_ptr += sizeof(policy.params.u.declined);\n+\t\tprocess_single_policy(&policy, ggu_conf);\n+\t}\n+\n+\t/* Process the IPv6 decline decisions. */\n+\tfor (j = 0; j < gguhdr->n2; j++) {\n+\t\tmemset(&policy, 0, sizeof(policy));\n+\t\tpolicy.state = GK_DECLINED;\n+\t\tpolicy.flow.proto = ETHER_TYPE_IPv6;\n+\t\trte_memcpy(&policy.flow.f.v6, policy_ptr,\n+\t\t\tsizeof(policy.flow.f.v6));\n+\t\tpolicy_ptr += sizeof(policy.flow.f.v6);\n+\t\trte_memcpy(&policy.params.u.declined, policy_ptr,\n+\t\t\tsizeof(policy.params.u.declined));\n+\t\tpolicy_ptr += sizeof(policy.params.u.declined);\n+\t\tprocess_single_policy(&policy, ggu_conf);\n+\t}\n+\n+\t/* Process the IPv4 granted decisions. */\n+\tfor (j = 0; j < gguhdr->n3; j++) {\n+\t\tmemset(&policy, 0, sizeof(policy));\n+\t\tpolicy.state = GK_GRANTED;\n+\t\tpolicy.flow.proto = ETHER_TYPE_IPv4;","path":"ggu/main.c","position":246,"original_position":246,"commit_id":"32115986389b9f70beaa2174ca2481f58bf51e3e","original_commit_id":"32115986389b9f70beaa2174ca2481f58bf51e3e","user":{"login":"mengxiang0811","id":4590679,"avatar_url":"https://avatars.githubusercontent.com/u/4590679?v=3","gravatar_id":"","url":"https://api.github.com/users/mengxiang0811","html_url":"https://github.com/mengxiang0811","followers_url":"https://api.github.com/users/mengxiang0811/followers","following_url":"https://api.github.com/users/mengxiang0811/following{/other_user}","gists_url":"https://api.github.com/users/mengxiang0811/gists{/gist_id}","starred_url":"https://api.github.com/users/mengxiang0811/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mengxiang0811/subscriptions","organizations_url":"https://api.github.com/users/mengxiang0811/orgs","repos_url":"https://api.github.com/users/mengxiang0811/repos","events_url":"https://api.github.com/users/mengxiang0811/events{/privacy}","received_events_url":"https://api.github.com/users/mengxiang0811/received_events","type":"User","site_admin":false},"body":"Done.","created_at":"2016-11-23T06:28:35Z","updated_at":"2016-11-23T06:28:35Z","html_url":"https://github.com/AltraMayor/gatekeeper/pull/9#discussion_r89261570","pull_request_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9","_links":{"self":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments/89261570"},"html":{"href":"https://github.com/AltraMayor/gatekeeper/pull/9#discussion_r89261570"},"pull_request":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9"}}},"pull_request":{"url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9","id":93281143,"html_url":"https://github.com/AltraMayor/gatekeeper/pull/9","diff_url":"https://github.com/AltraMayor/gatekeeper/pull/9.diff","patch_url":"https://github.com/AltraMayor/gatekeeper/pull/9.patch","issue_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/9","number":9,"state":"open","locked":false,"title":"Add IPIP encapsulation for GK, and a simple GK-GT Unit","user":{"login":"mengxiang0811","id":4590679,"avatar_url":"https://avatars.githubusercontent.com/u/4590679?v=3","gravatar_id":"","url":"https://api.github.com/users/mengxiang0811","html_url":"https://github.com/mengxiang0811","followers_url":"https://api.github.com/users/mengxiang0811/followers","following_url":"https://api.github.com/users/mengxiang0811/following{/other_user}","gists_url":"https://api.github.com/users/mengxiang0811/gists{/gist_id}","starred_url":"https://api.github.com/users/mengxiang0811/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mengxiang0811/subscriptions","organizations_url":"https://api.github.com/users/mengxiang0811/orgs","repos_url":"https://api.github.com/users/mengxiang0811/repos","events_url":"https://api.github.com/users/mengxiang0811/events{/privacy}","received_events_url":"https://api.github.com/users/mengxiang0811/received_events","type":"User","site_admin":false},"body":"The first patch adds support for IP over IP encapsulation for GK block, it supports both IPv4 and IPv6 addresses.  In this patch, the ``struct ip_flow`` is reorganized, since it will be shared by several blocks, so I chose to make it as a library.\r\n\r\nThe second patch adds a simple GK-GT Unit. The policies will be batched in a packet, for each policy decision, it first calculates the RSS hash value for that IP flow, then the last 7 bits will be used to index the Redirection table entries, where it stores the queue id. With the queue id, we may need to find an efficient way to lookup the corresponding GK block, who is responsible for that IP flow. For now, it simply iterates all the GK instances to find the matched one. With this patch, both RSS and ntuple filters support IPv6 as expected.","created_at":"2016-11-11T05:24:16Z","updated_at":"2016-11-23T06:28:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"18b2a3c2a9920811c18b1bc2b171d1fa2fd2afb0","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9/commits","review_comments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9/comments","review_comment_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/9/comments","statuses_url":"https://api.github.com/repos/AltraMayor/gatekeeper/statuses/32115986389b9f70beaa2174ca2481f58bf51e3e","head":{"label":"mengxiang0811:ipip-ggu","ref":"ipip-ggu","sha":"32115986389b9f70beaa2174ca2481f58bf51e3e","user":{"login":"mengxiang0811","id":4590679,"avatar_url":"https://avatars.githubusercontent.com/u/4590679?v=3","gravatar_id":"","url":"https://api.github.com/users/mengxiang0811","html_url":"https://github.com/mengxiang0811","followers_url":"https://api.github.com/users/mengxiang0811/followers","following_url":"https://api.github.com/users/mengxiang0811/following{/other_user}","gists_url":"https://api.github.com/users/mengxiang0811/gists{/gist_id}","starred_url":"https://api.github.com/users/mengxiang0811/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mengxiang0811/subscriptions","organizations_url":"https://api.github.com/users/mengxiang0811/orgs","repos_url":"https://api.github.com/users/mengxiang0811/repos","events_url":"https://api.github.com/users/mengxiang0811/events{/privacy}","received_events_url":"https://api.github.com/users/mengxiang0811/received_events","type":"User","site_admin":false},"repo":{"id":67135759,"name":"gatekeeper","full_name":"mengxiang0811/gatekeeper","owner":{"login":"mengxiang0811","id":4590679,"avatar_url":"https://avatars.githubusercontent.com/u/4590679?v=3","gravatar_id":"","url":"https://api.github.com/users/mengxiang0811","html_url":"https://github.com/mengxiang0811","followers_url":"https://api.github.com/users/mengxiang0811/followers","following_url":"https://api.github.com/users/mengxiang0811/following{/other_user}","gists_url":"https://api.github.com/users/mengxiang0811/gists{/gist_id}","starred_url":"https://api.github.com/users/mengxiang0811/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mengxiang0811/subscriptions","organizations_url":"https://api.github.com/users/mengxiang0811/orgs","repos_url":"https://api.github.com/users/mengxiang0811/repos","events_url":"https://api.github.com/users/mengxiang0811/events{/privacy}","received_events_url":"https://api.github.com/users/mengxiang0811/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mengxiang0811/gatekeeper","description":"First open source DoS protection system","fork":true,"url":"https://api.github.com/repos/mengxiang0811/gatekeeper","forks_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/forks","keys_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/teams","hooks_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/hooks","issue_events_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/issues/events{/number}","events_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/events","assignees_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/assignees{/user}","branches_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/branches{/branch}","tags_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/tags","blobs_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/git/refs{/sha}","trees_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/statuses/{sha}","languages_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/languages","stargazers_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/stargazers","contributors_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/contributors","subscribers_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/subscribers","subscription_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/subscription","commits_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/commits{/sha}","git_commits_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/git/commits{/sha}","comments_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/comments{/number}","issue_comment_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/issues/comments{/number}","contents_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/contents/{+path}","compare_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/merges","archive_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/downloads","issues_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/issues{/number}","pulls_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/pulls{/number}","milestones_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/milestones{/number}","notifications_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/labels{/name}","releases_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/releases{/id}","deployments_url":"https://api.github.com/repos/mengxiang0811/gatekeeper/deployments","created_at":"2016-09-01T13:55:13Z","updated_at":"2016-10-28T15:53:34Z","pushed_at":"2016-11-20T06:32:25Z","git_url":"git://github.com/mengxiang0811/gatekeeper.git","ssh_url":"git@github.com:mengxiang0811/gatekeeper.git","clone_url":"https://github.com/mengxiang0811/gatekeeper.git","svn_url":"https://github.com/mengxiang0811/gatekeeper","homepage":"","size":172,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"AltraMayor:master","ref":"master","sha":"60a0ed21d38668c8c9103ae499e6244436f21768","user":{"login":"AltraMayor","id":727014,"avatar_url":"https://avatars.githubusercontent.com/u/727014?v=3","gravatar_id":"","url":"https://api.github.com/users/AltraMayor","html_url":"https://github.com/AltraMayor","followers_url":"https://api.github.com/users/AltraMayor/followers","following_url":"https://api.github.com/users/AltraMayor/following{/other_user}","gists_url":"https://api.github.com/users/AltraMayor/gists{/gist_id}","starred_url":"https://api.github.com/users/AltraMayor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AltraMayor/subscriptions","organizations_url":"https://api.github.com/users/AltraMayor/orgs","repos_url":"https://api.github.com/users/AltraMayor/repos","events_url":"https://api.github.com/users/AltraMayor/events{/privacy}","received_events_url":"https://api.github.com/users/AltraMayor/received_events","type":"User","site_admin":false},"repo":{"id":62745741,"name":"gatekeeper","full_name":"AltraMayor/gatekeeper","owner":{"login":"AltraMayor","id":727014,"avatar_url":"https://avatars.githubusercontent.com/u/727014?v=3","gravatar_id":"","url":"https://api.github.com/users/AltraMayor","html_url":"https://github.com/AltraMayor","followers_url":"https://api.github.com/users/AltraMayor/followers","following_url":"https://api.github.com/users/AltraMayor/following{/other_user}","gists_url":"https://api.github.com/users/AltraMayor/gists{/gist_id}","starred_url":"https://api.github.com/users/AltraMayor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AltraMayor/subscriptions","organizations_url":"https://api.github.com/users/AltraMayor/orgs","repos_url":"https://api.github.com/users/AltraMayor/repos","events_url":"https://api.github.com/users/AltraMayor/events{/privacy}","received_events_url":"https://api.github.com/users/AltraMayor/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AltraMayor/gatekeeper","description":"First open source DDoS protection system","fork":false,"url":"https://api.github.com/repos/AltraMayor/gatekeeper","forks_url":"https://api.github.com/repos/AltraMayor/gatekeeper/forks","keys_url":"https://api.github.com/repos/AltraMayor/gatekeeper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AltraMayor/gatekeeper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AltraMayor/gatekeeper/teams","hooks_url":"https://api.github.com/repos/AltraMayor/gatekeeper/hooks","issue_events_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/events{/number}","events_url":"https://api.github.com/repos/AltraMayor/gatekeeper/events","assignees_url":"https://api.github.com/repos/AltraMayor/gatekeeper/assignees{/user}","branches_url":"https://api.github.com/repos/AltraMayor/gatekeeper/branches{/branch}","tags_url":"https://api.github.com/repos/AltraMayor/gatekeeper/tags","blobs_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/refs{/sha}","trees_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AltraMayor/gatekeeper/statuses/{sha}","languages_url":"https://api.github.com/repos/AltraMayor/gatekeeper/languages","stargazers_url":"https://api.github.com/repos/AltraMayor/gatekeeper/stargazers","contributors_url":"https://api.github.com/repos/AltraMayor/gatekeeper/contributors","subscribers_url":"https://api.github.com/repos/AltraMayor/gatekeeper/subscribers","subscription_url":"https://api.github.com/repos/AltraMayor/gatekeeper/subscription","commits_url":"https://api.github.com/repos/AltraMayor/gatekeeper/commits{/sha}","git_commits_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/commits{/sha}","comments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/comments{/number}","issue_comment_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/comments{/number}","contents_url":"https://api.github.com/repos/AltraMayor/gatekeeper/contents/{+path}","compare_url":"https://api.github.com/repos/AltraMayor/gatekeeper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AltraMayor/gatekeeper/merges","archive_url":"https://api.github.com/repos/AltraMayor/gatekeeper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AltraMayor/gatekeeper/downloads","issues_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues{/number}","pulls_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls{/number}","milestones_url":"https://api.github.com/repos/AltraMayor/gatekeeper/milestones{/number}","notifications_url":"https://api.github.com/repos/AltraMayor/gatekeeper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AltraMayor/gatekeeper/labels{/name}","releases_url":"https://api.github.com/repos/AltraMayor/gatekeeper/releases{/id}","deployments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/deployments","created_at":"2016-07-06T18:53:45Z","updated_at":"2016-11-04T13:44:41Z","pushed_at":"2016-11-20T06:32:26Z","git_url":"git://github.com/AltraMayor/gatekeeper.git","ssh_url":"git@github.com:AltraMayor/gatekeeper.git","clone_url":"https://github.com/AltraMayor/gatekeeper.git","svn_url":"https://github.com/AltraMayor/gatekeeper","homepage":"","size":84,"stargazers_count":3,"watchers_count":3,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":1,"forks":3,"open_issues":1,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9"},"html":{"href":"https://github.com/AltraMayor/gatekeeper/pull/9"},"issue":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/9"},"comments":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/9/comments"},"review_comments":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9/comments"},"review_comment":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/9/commits"},"statuses":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/statuses/32115986389b9f70beaa2174ca2481f58bf51e3e"}}}}
{"actor":{"display_login":"mengxiang0811"}}