Wiki source code of OpenVPN
Version 2.1 by Sebastian Marsching on 2022/05/29 13:40
Hide last authors
author | version | line-number | content |
---|---|---|---|
![]() |
1.1 | 1 | {{toc/}} |
2 | |||
3 | # MTU issues with OpenVPN | ||
4 | |||
5 | When packages that are travelling through an OpenVPN tunnel seem to disappear or connections (seem to not react any more (e.g. a webpage keeps loading and loading), this issues might be related to problems with the [MTU](http://en.wikipedia.org/wiki/Maximum_transmission_unit) settings. | ||
6 | |||
7 | fragment 1300 | ||
8 | mssfix | ||
9 | |||
10 | You might have to change the fragment value, but 1300 should be okay for a first try. | ||
11 | |||
![]() |
2.1 | 12 | See also: [[Path MTU Discovery issues|doc:Miscellaneous.Network.IP.WebHome|anchor="HPathMTUDiscoveryIssues"]] |
![]() |
1.1 | 13 | |
14 | # Authenticating with Active Directory | ||
15 | |||
16 | The following script can be used with OpenVPNs `auth-user-pass-verify` directive. The script reads the username and password from a file, so the `via-file` method should be specified. This script needs a fairly modern version of the `ldap3` module (it has been tested with version 1.3.1). | ||
17 | |||
18 | ```python | ||
19 | #!/usr/bin/python | ||
20 | |||
21 | # Authenticates an OpenVPN user against an Active Directory using LDAP. | ||
22 | # The authentication is successful when the specified credentials can be used to | ||
23 | # successfully connect with the LDAP service and the user is a member of the | ||
24 | # specified group. The membership check includes transitive memberships. | ||
25 | # The username is expected to be the SAM account name (without the domain). | ||
26 | # The password is expected to be the raw (unhashed) password. | ||
27 | # The username and password are read from the file specified as the only | ||
28 | # parameter to this script so that do not have to be passed through | ||
29 | # potentially unsafe environment variables. | ||
30 | |||
31 | import io | ||
32 | import ldap3 | ||
33 | import sys | ||
34 | |||
35 | # Find the principal (LDAP object) for the specified SAM account name. | ||
36 | # The SAM account name must not include the domain. | ||
37 | def find_principal_by_sam_account_name(ldap_connection, base_dn, sam_account_name): | ||
38 | if not ldap_connection.search(search_base = base_dn, search_filter = ('(sAMAccountName=' + ldap3.utils.conv.escape_filter_chars(sam_account_name) + ')')): | ||
39 | return None | ||
40 | if len(ldap_connection.entries) == 0: | ||
41 | return None | ||
42 | return ldap_connection.entries[0] | ||
43 | |||
44 | # This method is useful if we need all groups that the user is a member of. | ||
45 | def find_all_groups_principal_is_member_of(ldap_connection, base_dn, principal_dn): | ||
46 | if not ldap_connection.search(search_base = base_dn, search_filter = ('(member:1.2.840.113556.1.4.1941:=' + ldap3.utils.dn.safe_dn(principal_dn) + ')'), attributes = ldap3.ALL_ATTRIBUTES): | ||
47 | return None | ||
48 | return ldap_connection.entries | ||
49 | |||
50 | # Checks whether the specified principal (identified by its DN) is a member of | ||
51 | # the specified group (identified by its SID). | ||
52 | def is_principal_member_of_group(ldap_connection, base_dn, principal_dn, group_sid): | ||
53 | if not ldap_connection.search(search_base = base_dn, search_filter = ('(&(objectSid=' + ldap3.utils.conv.escape_filter_chars(group_sid) + ')(member:1.2.840.113556.1.4.1941:=' + ldap3.utils.dn.safe_dn(principal_dn) + '))')): | ||
54 | return False | ||
55 | return len(ldap_connection.entries) != 0 | ||
56 | |||
57 | |||
58 | # We use short timeouts so that we can failover to another domain controller | ||
59 | # when the first one fails. | ||
60 | connect_timeout = 1.0 | ||
61 | receive_timeout = 1.0 | ||
62 | base_dn = 'dc=ad,dc=example,dc=com' | ||
63 | # We can restrict the tree in which the principal must reside. If no | ||
64 | # restrictions are desired, we can simply use the base DN. | ||
65 | principal_search_base_dn = base_dn | ||
66 | domain = 'WINDOMAIN' | ||
67 | group_sid = 'S-1-5-21-1234567890-1234567890-1234567890-1234' | ||
68 | ldap_servers = [ 'dc-1.ad.example.com', 'dc-2.ad.example.com' ] | ||
69 | |||
70 | if len(sys.argv) != 2: | ||
71 | sys.exit(1) | ||
72 | |||
73 | user_pass_filename = sys.argv[1] | ||
74 | try: | ||
75 | user_pass_file = io.open(user_pass_filename) | ||
76 | username = user_pass_file.readline().strip() | ||
77 | password = user_pass_file.readline().strip() | ||
78 | user_pass_file.close() | ||
79 | except: | ||
80 | sys.exit(1) | ||
81 | |||
82 | ldap_username = domain + '\\' + username | ||
83 | |||
84 | connection = None | ||
85 | server = None | ||
86 | for ldap_server in ldap_servers: | ||
87 | try: | ||
88 | server = ldap3.Server(ldap_server, port = 636, use_ssl = True, connect_timeout = connect_timeout) | ||
89 | connection = ldap3.Connection(server, user = ldap_username, password = password, auto_bind = True, receive_timeout = receive_timeout) | ||
90 | break | ||
91 | except: | ||
92 | server = None | ||
93 | connection = None | ||
94 | |||
95 | if connection == None: | ||
96 | sys.exit(1) | ||
97 | |||
98 | try: | ||
99 | user_entry = find_principal_by_sam_account_name(connection, principal_search_base_dn, username) | ||
100 | if user_entry == None: | ||
101 | sys.exit(1) | ||
102 | user_dn = user_entry.entry_get_dn() | ||
103 | is_group_member = is_principal_member_of_group(connection, base_dn, user_dn, group_sid) | ||
104 | except: | ||
105 | sys.exit(1) | ||
106 | |||
107 | if is_group_member: | ||
108 | sys.exit(0) | ||
109 | else: | ||
110 | sys.exit(1) | ||
111 | ``` |