1
1
'''
2
-
3
2
#################################
4
- ## ##
5
- ## one.com DDNS Script ##
6
- ## ##
3
+ ## ##
4
+ ## one.com DDNS Script ##
5
+ ## ##
7
6
#################################
8
- | Version | 2.4 |
7
+ | Version | 2.4 |
9
8
+--------------+----------------+
10
- | Last Updated | 2023-10-05 |
9
+ | Last Updated | 2023-10-05 |
11
10
+--------------+----------------+
12
11
13
12
+----------------+-------------------------+
17
16
+----------------+-------------------------+
18
17
19
18
20
-
21
-
22
19
Note:
23
20
This script is not very fail proof.
24
21
Very few possible exceptions are handled, something as simple
27
24
28
25
If you have any problems or suggestions, please open an issue
29
26
on github or send me an email (main@lugico.de)
30
-
31
27
'''
32
28
29
+ import modules .dns_utils as dns_utils
30
+ import modules .one_com_config as config
31
+ import modules .one_com_api as one_com_api
32
+ import modules .logger as logger_module # Import the logger module
33
+ import logging
34
+
35
+ logger = logger_module .setup_logging () # Setup logging
36
+
37
+ # #################################
38
+ # ## ##
39
+ # ## HARDCODED VALUES ##
40
+ # ## ##
41
+ # #################################
42
+ # If you wish to hardcode values below and disable cli/env parsing set validate_required=False
43
+ settings = config .parse_config (validate_required = True )
44
+
45
+ # ONE.COM LOGIN
46
+ USERNAME = settings .username
47
+ PASSWORD = settings .password
48
+
49
+ # YOUR DOMAIN (NOT www.example.com, www2.example.com)
50
+ DOMAINS = settings .domains
51
+
52
+ # YOUR IP ADDRESS. DEFAULTS TO RESOLVING VIA ipify.org, set to 'ARG' to take from script argument
53
+ IP = settings .ip
54
+
55
+ # FORCE UPDATE DNS RECORD
56
+ FORCE_UPDATE = settings .force_update
57
+
58
+ # TTL VALUE FOR DNS RECORD
59
+ TTL = settings .ttl
60
+
61
+ # SKIP CONFIRMATION
62
+ SKIP_CONFIRMATION = settings .skip_confirmation
63
+
64
+ # Create login session - Session is created only once outside the domain loop
65
+ s = one_com_api .login_session (USERNAME , PASSWORD )
66
+
67
+ # loop through list of domains
68
+ for DOMAIN in DOMAINS :
69
+ print ()
70
+ logger .info (f"Processing domain: { DOMAIN } " )
71
+ one_com_api .select_admin_domain (s , DOMAIN ) # Select domain at the beginning of each domain loop
72
+
73
+ # get dns records for the current domain
74
+ records = one_com_api .get_custom_records (s , DOMAIN )
75
+
76
+ # Check current IP from DNS
77
+ logger .info (f"Attempting to get current DNS IP for: { DOMAIN } " )
78
+ current_dns_ip_info = dns_utils .get_ip_and_ttl (DOMAIN )
79
+
80
+ if current_dns_ip_info :
81
+ current_dns_ip , current_ttl = current_dns_ip_info
82
+ logger .info (f"Current DNS IP for { DOMAIN } : { current_dns_ip } , TTL: { current_ttl } " )
83
+
84
+ if not FORCE_UPDATE and current_dns_ip == IP :
85
+ logger .info (f"IP Address hasn't changed for { DOMAIN } . Aborting update for this domain." )
86
+ continue
87
+
88
+ # change ip address
89
+ record_obj = one_com_api .find_id_by_subdomain (records , DOMAIN )
90
+ if record_obj is None :
91
+ logger .error (f"Record '{ DOMAIN } ' could not be found." )
92
+ continue
93
+
94
+ # Ask for confirmation before changing
95
+ logger .warning (f"Changing IP for { DOMAIN } from { current_dns_ip } to { IP } with TTL { TTL } ." )
96
+ if settings .skip_confirmation :
97
+ one_com_api .change_ip (s , record_obj , DOMAIN , IP , TTL )
98
+ else :
99
+ confirmation = input ("Do you want to proceed? (y/n): " )
100
+ if confirmation .lower () == 'y' :
101
+ one_com_api .change_ip (s , record_obj , DOMAIN , IP , TTL )
102
+ else :
103
+ logger .info (f"Update for { DOMAIN } cancelled." )
33
104
34
-
35
- # YOUR ONE.COM LOGIN
36
- USERNAME = "email.address@example.com"
37
- PASSWORD = "Your Beautiful Password"
38
-
39
- # YOUR DOMAIN ( NOT www.example.com, only example.com )"
40
- DOMAIN = "example.com"
41
-
42
- # LIST OF SUBDOMAINS YOU WANT POINTING TO YOUR IP
43
- SUBDOMAINS = ["myddns" ]
44
- # SUBDOMAINS = ["mutiple", "subdomains"]
45
-
46
-
47
- # YOUR IP ADDRESS.
48
- IP = 'AUTO'
49
- # '127.0.0.1' -> IP Address
50
- # 'AUTO' -> Automatically detect using ipify.org
51
- # 'ARG' -> Read from commandline argument ($ python3 ddns.py 127.0.0.1)
52
-
53
-
54
- # CHECK IF IP ADDRESS HAS CHANGED SINCE LAST SCRIPT EXECUTION?
55
- CHECK_IP_CHANGE = True
56
- # True = only continue when IP has changed
57
- # False = always continue
58
-
59
- # PATH WHERE THE LAST IP SHOULD BE SAVED INBETWEEN SCRIPT EXECUTIONS
60
- # not needed CHECK_IP_CHANGE is false
61
- LAST_IP_FILE = "lastip.txt"
62
-
63
-
64
- import requests
65
- import json
66
- import sys
67
-
68
- if IP == 'AUTO' :
69
- print ("Fetching IP Address..." )
70
- try :
71
- IP = requests .get ("https://api.ipify.org/" ).text
72
- except requests .ConnectionError :
73
- raise SystemExit ("Failed to get IP Address from ipify" )
74
- print (f"Detected IP: { IP } " )
75
- elif IP == 'ARG' :
76
- if (len (sys .argv ) < 2 ):
77
- raise SystemExit ('No IP Address provided in commandline arguments' )
78
105
else :
79
- IP = sys .argv [1 ]
80
-
81
- if CHECK_IP_CHANGE :
82
- try :
83
- # try to read file
84
- with open (LAST_IP_FILE ,"r" ) as f :
85
- if (IP == f .read ()):
86
- # abort if ip in file is same as current
87
- print ("IP Address hasn't changed. Aborting" )
88
- exit ()
89
- except IOError :
90
- pass
91
-
92
- # write current ip to file
93
- with open (LAST_IP_FILE ,"w" ) as f :
94
- f .write (IP )
95
-
96
-
97
- def findBetween (haystack , needle1 , needle2 ):
98
- index1 = haystack .find (needle1 ) + len (needle1 )
99
- index2 = haystack .find (needle2 , index1 + 1 )
100
- return haystack [index1 : index2 ]
101
-
102
-
103
- # will create a requests session and log you into your one.com account in that session
104
- def loginSession (USERNAME , PASSWORD , TARGET_DOMAIN = '' ):
105
- print ("Logging in..." )
106
-
107
- # create requests session
108
- session = requests .session ()
109
-
110
- # get admin panel to be redirected to login page
111
- redirectmeurl = "https://www.one.com/admin/"
112
- try :
113
- r = session .get (redirectmeurl )
114
- except requests .ConnectionError :
115
- raise SystemExit ("Connection to one.com failed." )
116
-
117
- # find url to post login credentials to from form action attribute
118
- substrstart = '<form id="kc-form-login" class="Login-form login autofill" onsubmit="login.disabled = true; return true;" action="'
119
- substrend = '"'
120
- posturl = findBetween (r .text , substrstart , substrend ).replace ('&' ,'&' )
121
-
122
- # post login data
123
- logindata = {'username' : USERNAME , 'password' : PASSWORD , 'credentialId' : '' }
124
- response = session .post (posturl , data = logindata )
125
- if response .text .find ("Invalid username or password." ) != - 1 :
126
- print ("!!! - Invalid credentials. Exiting" )
127
- exit (1 )
128
-
129
- print ("Login successful." )
130
-
131
- # For accounts with multiple domains it seems to still be needed to select which target domain to operate on.
132
- if TARGET_DOMAIN :
133
- print ("Setting active domain to: {}" .format (TARGET_DOMAIN ))
134
- selectAdminDomain (session , TARGET_DOMAIN )
135
-
136
- return session
137
-
138
-
139
- def selectAdminDomain (session , DOMAIN ):
140
- request_str = "https://www.one.com/admin/select-admin-domain.do?domain={}" .format (DOMAIN )
141
- session .get (request_str )
142
-
143
-
144
- # gets all DNS records on your domain.
145
- def getCustomRecords (session , DOMAIN ):
146
- print ("Getting Records" )
147
- getres = session .get ("https://www.one.com/admin/api/domains/" + DOMAIN + "/dns/custom_records" ).text
148
- if len (getres ) == 0 :
149
- print ("!!! - No records found. Exiting" )
150
- exit ()
151
- return json .loads (getres )["result" ]["data" ]
152
-
153
-
154
- # finds the record id of a record from it's subdomain
155
- def findIdBySubdomain (records , subdomain ):
156
- print ("searching domain '" + subdomain + "'" )
157
- for obj in records :
158
- if obj ["attributes" ]["prefix" ] == subdomain :
159
- print ("Found Domain '" + subdomain + "': " + obj ["id" ])
160
- return obj ["id" ]
161
- return ""
162
-
163
-
164
- # changes the IP Address of a TYPE A record. Default TTL=3800
165
- def changeIP (session , ID , DOMAIN , SUBDOMAIN , IP , TTL = 3600 ):
166
- print ("Changing IP on subdomain '" + SUBDOMAIN + "' - ID '" + ID + "' TO NEW IP '" + IP + "'" )
167
-
168
- tosend = {"type" :"dns_service_records" ,"id" :ID ,"attributes" :{"type" :"A" ,"prefix" :SUBDOMAIN ,"content" :IP ,"ttl" :TTL }}
169
-
170
- dnsurl = "https://www.one.com/admin/api/domains/" + DOMAIN + "/dns/custom_records/" + ID
171
-
172
- sendheaders = {'Content-Type' : 'application/json' }
173
-
174
- session .patch (dnsurl , data = json .dumps (tosend ), headers = sendheaders )
175
-
176
- print ("Sent Change IP Request" )
177
-
178
-
179
-
180
- # Create login session
181
- s = loginSession (USERNAME , PASSWORD , DOMAIN )
182
-
183
- # get dns records
184
- records = getCustomRecords (s , DOMAIN )
185
- #print(records)
186
-
187
- # loop through list of subdomains
188
- for subdomain in SUBDOMAINS :
189
- #change ip address
190
- recordid = findIdBySubdomain (records , subdomain )
191
- if recordid == "" :
192
- print ("!!! - Record '" + subdomain + "' could not be found." )
193
- continue
194
- changeIP (s , recordid , DOMAIN , subdomain , IP , 600 )
106
+ logger .warning (f"Could not retrieve current DNS IP for { DOMAIN } after multiple retries. Proceeding with update anyway." )
107
+ record_obj = one_com_api .find_id_by_subdomain (records , DOMAIN )
108
+ if record_obj is None :
109
+ logger .error (f"Record '{ DOMAIN } ' could not be found." )
110
+ continue
111
+
112
+ logger .info (f"Changing IP for { DOMAIN } to { IP } with TTL { TTL } ." )
113
+ if settings .skip_confirmation :
114
+ one_com_api .change_ip (s , record_obj , DOMAIN , IP , TTL )
115
+ else :
116
+ confirmation = input ("Do you want to proceed? (y/n): " )
117
+ if confirmation .lower () == 'y' :
118
+ one_com_api .change_ip (s , record_obj , DOMAIN , IP , TTL )
119
+ else :
120
+ logger .info (f"Update for { DOMAIN } cancelled." )
121
+
122
+ logger .info ("DDNS update process completed." )
0 commit comments