{"action":"created","comment":{"url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/comments/60841289","id":60841289,"diff_hunk":"@@ -0,0 +1,153 @@\n+#!/usr/bin/python\r\n+# encoding: utf-8\r\n+\r\n+# (c) 2016, Nathan Davison <ndavison85@gmail.com>\r\n+#\r\n+# This file is part of Ansible\r\n+#\r\n+# Ansible is free software: you can redistribute it and/or modify\r\n+# it under the terms of the GNU General Public License as published by\r\n+# the Free Software Foundation, either version 3 of the License, or\r\n+# (at your option) any later version.\r\n+#\r\n+# Ansible is distributed in the hope that it will be useful,\r\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n+# GNU General Public License for more details.\r\n+#\r\n+# You should have received a copy of the GNU General Public License\r\n+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\r\n+\r\n+DOCUMENTATION = '''\r\n+---\r\n+module: portenforce\r\n+author:\r\n+    - '\"Nathan Davison (@ndavison)\" <ndavison85@gmail.com>'\r\n+version_added: \"2.1\"\r\n+description:\r\n+    - Kill processes listening on TCP and UDP ports not defined in the whitelists.\r\n+short_description: Kill processes listening on TCP and UDP ports not defined in the whitelists.\r\n+options:\r\n+  whitelist_tcp:\r\n+    description:\r\n+      - A list of TCP ports to allow.\r\n+    required: false\r\n+    type: \"list\"\r\n+  whitelist_udp:\r\n+    description:\r\n+      - A list of UDP ports to allow.\r\n+    required: false\r\n+    type: \"list\"\r\n+'''\r\n+\r\n+EXAMPLES = '''\r\n+- name: only allow TCP 80, 443, and 22\r\n+  portenforce:\r\n+    whitelist_tcp:\r\n+      - 22\r\n+      - 80\r\n+      - 443\r\n+'''\r\n+\r\n+RETURN = '''\r\n+killed:\r\n+  description: A list of pids that were killed.\r\n+  type: list\r\n+  contains:\r\n+    pid:\r\n+      description: The pid of a killed process.\r\n+      type: int\r\n+      sample: 1223\r\n+    port:\r\n+      description: The port the killed pid was listening on.\r\n+      type: int\r\n+      sample: 443\r\n+    proto:\r\n+      description: The protocol, TCP or UDP, of the listening connection.\r\n+      type: string\r\n+      sample: 'tcp'\r\n+'''\r\n+\r\n+import re\r\n+from subprocess import Popen, PIPE\r\n+\r\n+def netStatParse(raw):\r\n+    results = list()\r\n+    for line in iter(raw.splitlines()):\r\n+        listening_search = re.search('[^ ]+:[^ ]+', line)\r\n+        if listening_search:\r\n+            splitted = line.split()\r\n+            conns = re.search('[^ ]+:([^ ]+)', splitted[3])\r\n+            if 'tcp' in splitted[0]:\r\n+                proto = 'tcp'\r\n+                pidstr = splitted[6]\r\n+            else:\r\n+                proto = 'udp'\r\n+                pidstr = splitted[5]\r\n+            pids = re.search('([0-9]+)/', pidstr)\r\n+            if conns and pids:\r\n+                port = conns.group(1)\r\n+                pid = pids.group(1)\r\n+                result = dict(pid=int(pid), port=int(port), proto=proto)\r\n+                if result not in results:\r\n+                    results.append(result)\r\n+            elif not pids:\r\n+                raise EnvironmentError('Could not get the pids for the listening ports - possibly a permission issue')\r\n+    return results\r\n+\r\n+def applyWhitelist(portspids, whitelist=list()):\r\n+    kill_pids = list()\r\n+    for p in portspids:\r\n+        if int(p['port']) not in whitelist and str(p['port']) not in whitelist:\r\n+            if dict(pid=p['pid'], port=p['port'], proto=p['proto']) not in kill_pids:\r\n+                kill_pids.append(dict(pid=p['pid'], port=p['port'], proto=p['proto']))\r\n+    return kill_pids\r\n+\r\n+def main():\r\n+\r\n+    module = AnsibleModule(\r\n+        argument_spec = dict(\r\n+            whitelist_tcp = dict(required=False, type='list', default=list()),\r\n+            whitelist_udp = dict(required=False, type='list', default=list())\r\n+        ),\r\n+        supports_check_mode=True\r\n+    )\r\n+\r\n+    result = {}\r\n+    result['changed'] = False\r\n+    result['killed'] = list()\r\n+\r\n+    try:\r\n+        # which TCP ports are listening for connections?\r\n+        p1 = Popen(['netstat', '-plnt'], stdout=PIPE, stderr=PIPE)\r","path":"system/portenforce.py","position":137,"original_position":122,"commit_id":"1508dd48ce22b3adbd623f91959c57cd8c1c3209","original_commit_id":"d3343e3b5b89c5a81982017f31aa098491fa8029","user":{"login":"ndavison","id":1152676,"avatar_url":"https://avatars.githubusercontent.com/u/1152676?v=3","gravatar_id":"","url":"https://api.github.com/users/ndavison","html_url":"https://github.com/ndavison","followers_url":"https://api.github.com/users/ndavison/followers","following_url":"https://api.github.com/users/ndavison/following{/other_user}","gists_url":"https://api.github.com/users/ndavison/gists{/gist_id}","starred_url":"https://api.github.com/users/ndavison/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ndavison/subscriptions","organizations_url":"https://api.github.com/users/ndavison/orgs","repos_url":"https://api.github.com/users/ndavison/repos","events_url":"https://api.github.com/users/ndavison/events{/privacy}","received_events_url":"https://api.github.com/users/ndavison/received_events","type":"User","site_admin":false},"body":"Would it be acceptable to add a note about not being compatible with freebsd?","created_at":"2016-04-24T08:53:28Z","updated_at":"2016-04-24T08:53:28Z","html_url":"https://github.com/ansible/ansible-modules-extras/pull/2069#discussion_r60841289","pull_request_url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069","_links":{"self":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/comments/60841289"},"html":{"href":"https://github.com/ansible/ansible-modules-extras/pull/2069#discussion_r60841289"},"pull_request":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069"}}},"pull_request":{"url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069","id":67174676,"html_url":"https://github.com/ansible/ansible-modules-extras/pull/2069","diff_url":"https://github.com/ansible/ansible-modules-extras/pull/2069.diff","patch_url":"https://github.com/ansible/ansible-modules-extras/pull/2069.patch","issue_url":"https://api.github.com/repos/ansible/ansible-modules-extras/issues/2069","number":2069,"state":"open","locked":false,"title":"Added portenforce module","user":{"login":"ndavison","id":1152676,"avatar_url":"https://avatars.githubusercontent.com/u/1152676?v=3","gravatar_id":"","url":"https://api.github.com/users/ndavison","html_url":"https://github.com/ndavison","followers_url":"https://api.github.com/users/ndavison/followers","following_url":"https://api.github.com/users/ndavison/following{/other_user}","gists_url":"https://api.github.com/users/ndavison/gists{/gist_id}","starred_url":"https://api.github.com/users/ndavison/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ndavison/subscriptions","organizations_url":"https://api.github.com/users/ndavison/orgs","repos_url":"https://api.github.com/users/ndavison/repos","events_url":"https://api.github.com/users/ndavison/events{/privacy}","received_events_url":"https://api.github.com/users/ndavison/received_events","type":"User","site_admin":false},"body":"##### ISSUE TYPE\r\n - New Module Pull Request\r\n\r\n##### COMPONENT NAME\r\nportenforce\r\n\r\n##### ANSIBLE VERSION\r\n```\r\nansible 2.1.0 (devel 3c3061378b) last updated 2016/04/18 19:52:38 (GMT +1100)\r\n  lib/ansible/modules/core: (detached HEAD 5409ed1b28) last updated 2016/04/18 19:52:51 (GMT +1100)\r\n  lib/ansible/modules/extras: (detached HEAD 3afe117730) last updated 2016/04/18 19:53:03 (GMT +1100)\r\n  config file = /etc/ansible/ansible.cfg\r\n  configured module search path = Default w/o overrides\r\n```\r\n\r\n##### SUMMARY\r\nThis module allows the user to define whitelists for TCP and/or UDP ports that a host is allowed to have processes listening on, killing processes that are listening on a port not in the whitelist. This is designed to be a small component in a larger offensive security Ansible setup.","created_at":"2016-04-20T12:03:46Z","updated_at":"2016-04-24T08:53:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0bc72f641c517b5ede5e3695a25d6e531588bda4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069/commits","review_comments_url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069/comments","review_comment_url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ansible/ansible-modules-extras/issues/2069/comments","statuses_url":"https://api.github.com/repos/ansible/ansible-modules-extras/statuses/1508dd48ce22b3adbd623f91959c57cd8c1c3209","head":{"label":"ndavison:feature/portenforce","ref":"feature/portenforce","sha":"1508dd48ce22b3adbd623f91959c57cd8c1c3209","user":{"login":"ndavison","id":1152676,"avatar_url":"https://avatars.githubusercontent.com/u/1152676?v=3","gravatar_id":"","url":"https://api.github.com/users/ndavison","html_url":"https://github.com/ndavison","followers_url":"https://api.github.com/users/ndavison/followers","following_url":"https://api.github.com/users/ndavison/following{/other_user}","gists_url":"https://api.github.com/users/ndavison/gists{/gist_id}","starred_url":"https://api.github.com/users/ndavison/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ndavison/subscriptions","organizations_url":"https://api.github.com/users/ndavison/orgs","repos_url":"https://api.github.com/users/ndavison/repos","events_url":"https://api.github.com/users/ndavison/events{/privacy}","received_events_url":"https://api.github.com/users/ndavison/received_events","type":"User","site_admin":false},"repo":{"id":56673627,"name":"ansible-modules-extras","full_name":"ndavison/ansible-modules-extras","owner":{"login":"ndavison","id":1152676,"avatar_url":"https://avatars.githubusercontent.com/u/1152676?v=3","gravatar_id":"","url":"https://api.github.com/users/ndavison","html_url":"https://github.com/ndavison","followers_url":"https://api.github.com/users/ndavison/followers","following_url":"https://api.github.com/users/ndavison/following{/other_user}","gists_url":"https://api.github.com/users/ndavison/gists{/gist_id}","starred_url":"https://api.github.com/users/ndavison/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ndavison/subscriptions","organizations_url":"https://api.github.com/users/ndavison/orgs","repos_url":"https://api.github.com/users/ndavison/repos","events_url":"https://api.github.com/users/ndavison/events{/privacy}","received_events_url":"https://api.github.com/users/ndavison/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ndavison/ansible-modules-extras","description":"Ansible extra modules - these modules ship with ansible","fork":true,"url":"https://api.github.com/repos/ndavison/ansible-modules-extras","forks_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/forks","keys_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/teams","hooks_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/hooks","issue_events_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/issues/events{/number}","events_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/events","assignees_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/assignees{/user}","branches_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/branches{/branch}","tags_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/tags","blobs_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/git/refs{/sha}","trees_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/statuses/{sha}","languages_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/languages","stargazers_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/stargazers","contributors_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/contributors","subscribers_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/subscribers","subscription_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/subscription","commits_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/commits{/sha}","git_commits_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/git/commits{/sha}","comments_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/comments{/number}","issue_comment_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/issues/comments{/number}","contents_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/contents/{+path}","compare_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/merges","archive_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/downloads","issues_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/issues{/number}","pulls_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/pulls{/number}","milestones_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/milestones{/number}","notifications_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/labels{/name}","releases_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/releases{/id}","deployments_url":"https://api.github.com/repos/ndavison/ansible-modules-extras/deployments","created_at":"2016-04-20T09:23:43Z","updated_at":"2016-04-20T09:23:47Z","pushed_at":"2016-04-24T08:45:02Z","git_url":"git://github.com/ndavison/ansible-modules-extras.git","ssh_url":"git@github.com:ndavison/ansible-modules-extras.git","clone_url":"https://github.com/ndavison/ansible-modules-extras.git","svn_url":"https://github.com/ndavison/ansible-modules-extras","homepage":"","size":7086,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"devel"}},"base":{"label":"ansible:devel","ref":"devel","sha":"451420b7e8611d3a88a4b567c167567e71a8a359","user":{"login":"ansible","id":1507452,"avatar_url":"https://avatars.githubusercontent.com/u/1507452?v=3","gravatar_id":"","url":"https://api.github.com/users/ansible","html_url":"https://github.com/ansible","followers_url":"https://api.github.com/users/ansible/followers","following_url":"https://api.github.com/users/ansible/following{/other_user}","gists_url":"https://api.github.com/users/ansible/gists{/gist_id}","starred_url":"https://api.github.com/users/ansible/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ansible/subscriptions","organizations_url":"https://api.github.com/users/ansible/orgs","repos_url":"https://api.github.com/users/ansible/repos","events_url":"https://api.github.com/users/ansible/events{/privacy}","received_events_url":"https://api.github.com/users/ansible/received_events","type":"Organization","site_admin":false},"repo":{"id":24474138,"name":"ansible-modules-extras","full_name":"ansible/ansible-modules-extras","owner":{"login":"ansible","id":1507452,"avatar_url":"https://avatars.githubusercontent.com/u/1507452?v=3","gravatar_id":"","url":"https://api.github.com/users/ansible","html_url":"https://github.com/ansible","followers_url":"https://api.github.com/users/ansible/followers","following_url":"https://api.github.com/users/ansible/following{/other_user}","gists_url":"https://api.github.com/users/ansible/gists{/gist_id}","starred_url":"https://api.github.com/users/ansible/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ansible/subscriptions","organizations_url":"https://api.github.com/users/ansible/orgs","repos_url":"https://api.github.com/users/ansible/repos","events_url":"https://api.github.com/users/ansible/events{/privacy}","received_events_url":"https://api.github.com/users/ansible/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ansible/ansible-modules-extras","description":"Ansible extra modules - these modules ship with ansible","fork":false,"url":"https://api.github.com/repos/ansible/ansible-modules-extras","forks_url":"https://api.github.com/repos/ansible/ansible-modules-extras/forks","keys_url":"https://api.github.com/repos/ansible/ansible-modules-extras/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ansible/ansible-modules-extras/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ansible/ansible-modules-extras/teams","hooks_url":"https://api.github.com/repos/ansible/ansible-modules-extras/hooks","issue_events_url":"https://api.github.com/repos/ansible/ansible-modules-extras/issues/events{/number}","events_url":"https://api.github.com/repos/ansible/ansible-modules-extras/events","assignees_url":"https://api.github.com/repos/ansible/ansible-modules-extras/assignees{/user}","branches_url":"https://api.github.com/repos/ansible/ansible-modules-extras/branches{/branch}","tags_url":"https://api.github.com/repos/ansible/ansible-modules-extras/tags","blobs_url":"https://api.github.com/repos/ansible/ansible-modules-extras/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ansible/ansible-modules-extras/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ansible/ansible-modules-extras/git/refs{/sha}","trees_url":"https://api.github.com/repos/ansible/ansible-modules-extras/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ansible/ansible-modules-extras/statuses/{sha}","languages_url":"https://api.github.com/repos/ansible/ansible-modules-extras/languages","stargazers_url":"https://api.github.com/repos/ansible/ansible-modules-extras/stargazers","contributors_url":"https://api.github.com/repos/ansible/ansible-modules-extras/contributors","subscribers_url":"https://api.github.com/repos/ansible/ansible-modules-extras/subscribers","subscription_url":"https://api.github.com/repos/ansible/ansible-modules-extras/subscription","commits_url":"https://api.github.com/repos/ansible/ansible-modules-extras/commits{/sha}","git_commits_url":"https://api.github.com/repos/ansible/ansible-modules-extras/git/commits{/sha}","comments_url":"https://api.github.com/repos/ansible/ansible-modules-extras/comments{/number}","issue_comment_url":"https://api.github.com/repos/ansible/ansible-modules-extras/issues/comments{/number}","contents_url":"https://api.github.com/repos/ansible/ansible-modules-extras/contents/{+path}","compare_url":"https://api.github.com/repos/ansible/ansible-modules-extras/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ansible/ansible-modules-extras/merges","archive_url":"https://api.github.com/repos/ansible/ansible-modules-extras/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ansible/ansible-modules-extras/downloads","issues_url":"https://api.github.com/repos/ansible/ansible-modules-extras/issues{/number}","pulls_url":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls{/number}","milestones_url":"https://api.github.com/repos/ansible/ansible-modules-extras/milestones{/number}","notifications_url":"https://api.github.com/repos/ansible/ansible-modules-extras/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ansible/ansible-modules-extras/labels{/name}","releases_url":"https://api.github.com/repos/ansible/ansible-modules-extras/releases{/id}","deployments_url":"https://api.github.com/repos/ansible/ansible-modules-extras/deployments","created_at":"2014-09-25T20:28:42Z","updated_at":"2016-04-23T00:06:29Z","pushed_at":"2016-04-24T08:45:04Z","git_url":"git://github.com/ansible/ansible-modules-extras.git","ssh_url":"git@github.com:ansible/ansible-modules-extras.git","clone_url":"https://github.com/ansible/ansible-modules-extras.git","svn_url":"https://github.com/ansible/ansible-modules-extras","homepage":"","size":13637,"stargazers_count":561,"watchers_count":561,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1132,"mirror_url":null,"open_issues_count":549,"forks":1132,"open_issues":549,"watchers":561,"default_branch":"devel"}},"_links":{"self":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069"},"html":{"href":"https://github.com/ansible/ansible-modules-extras/pull/2069"},"issue":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/issues/2069"},"comments":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/issues/2069/comments"},"review_comments":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069/comments"},"review_comment":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/pulls/2069/commits"},"statuses":{"href":"https://api.github.com/repos/ansible/ansible-modules-extras/statuses/1508dd48ce22b3adbd623f91959c57cd8c1c3209"}}}}