|
59 |
'''Return a dict with all necessary values for ipchange read from the current |
59 |
'''Return a dict with all necessary values for ipchange read from the current |
60 |
status of the system.''' |
60 |
status of the system.''' |
61 |
|
61 |
|
62 |
# ignore link local addresses (no DHCP address received) |
62 |
# ignore link local or loopback addresses (no DHCP address received) |
63 |
network = ipaddress.IPv4Network(f'{ip}/{netmask}', False) |
63 |
network = ipaddress.ip_network(f'{ip}/{netmask}', False) |
64 |
if network.is_link_local: |
64 |
if network.is_link_local or network.is_loopback: |
65 |
MODULE.error('Ignore link local address change.') |
65 |
MODULE.error('Ignore link local or loopback address change.') |
66 |
return |
66 |
return |
67 |
|
67 |
|
|
|
68 |
# set attribute aRecord(<split>.|<trim>0) or aAAARecord(<split>:|<trim>0000) for IP version 4 or 6 |
69 |
if network.version == 4: |
70 |
attribute = 'aRecord' |
71 |
sattribute = '.' |
72 |
tattribute = '0' |
73 |
if network.version == 6: |
74 |
attribute = 'aAAARecord' |
75 |
sattribute = ':' |
76 |
tattribute = '0000' |
77 |
|
68 |
lo, position = univention.admin.uldap.getAdminConnection() |
78 |
lo, position = univention.admin.uldap.getAdminConnection() |
69 |
hmodule = univention.admin.modules.get('dns/host_record') |
79 |
hmodule = univention.admin.modules.get('dns/host_record') |
|
|
80 |
rmodule = univention.admin.modules.get('dns/reverse_zone') |
81 |
fmodule = univention.admin.modules.get('dns/forward_zone') |
70 |
cmodule = univention.admin.modules.get(f'computers/{role}') |
82 |
cmodule = univention.admin.modules.get(f'computers/{role}') |
|
|
83 |
server = cmodule.object(None, lo, position, self.user_dn) |
84 |
server.open() |
85 |
|
86 |
# get the current server status filtert by IP version and init fqdns to change the host records too |
87 |
saddresses = [entry for entry in server.get('ip') if ipaddress.ip_address(entry).version == network.version] |
88 |
fqdns = [server.get('fqdn')] |
89 |
|
90 |
if ip: |
91 |
naddress = ipaddress.ip_address(ip).exploded |
92 |
if oldip: |
93 |
oaddress = ipaddress.ip_address(oldip).exploded |
94 |
if oldip and oaddress != naddress: |
95 |
for address in [oaddress, oldip]: |
96 |
if address not in saddresses: |
97 |
saddresses.append(address) |
98 |
|
99 |
# check if already used by host record ( raise by first match ) |
100 |
res = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', filter=filter_format(f'(|({attribute}=%s)({attribute}=%s))', (naddress,ip))) |
101 |
for name in [entry['name'] for entry in res if 'name' in entry]: |
102 |
raise BadRequest(f'The IP address is already in use by host record for : {name}') |
103 |
|
104 |
# change host records first ( we need to prepare this for a new pTRRecord ) |
105 |
ucr.load() |
106 |
|
107 |
# FIXME: This should be done for UCS-in-AD domains as well! |
108 |
# FIXED? Works, but it is't stable! |
109 |
# ( Sometimes the S4 connector resync old adresses. Do we have to wait for a replication? ) |
110 |
if 'samba' in ucr.get('dns/backend'): |
111 |
for host in ['gc._msdcs','DomainDnsZones','ForestDnsZones']: |
112 |
fqdns.append(f'{host}.%s' % ucr.get('domainname')) |
113 |
|
114 |
if ucr.is_true('ucs/server/sso/autoregistraton', True): |
115 |
fqdns.append(ucr.get('ucs/server/sso/fqdn')) |
71 |
|
116 |
|
72 |
# check if already used |
117 |
for fqdn in fqdns: |
73 |
res = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', filter=filter_format('aRecord=%s', (ip,))) |
118 |
forwardobjects = univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=None) |
74 |
used_by = [entry['name'] for entry in res if 'name' in entry] |
119 |
for forwardobject in forwardobjects: |
75 |
if used_by: |
120 |
zone = forwardobject.get('zone') |
76 |
raise BadRequest(f'The IP address is already in use by host record(s) for: {", ".join(used_by)}') |
121 |
if not fqdn.endswith(zone): |
|
|
122 |
continue |
123 |
name = fqdn[:-(len(zone) + 1)] |
124 |
for address in saddresses: |
125 |
records = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', superordinate=forwardobject, filter=filter_format(f'(&(relativeDomainName=%s)({attribute}=%s))', (name, address))) |
126 |
for record in records: |
127 |
record.open() |
128 |
record['a'].remove(address) |
129 |
record['a'].append(naddress) |
130 |
record.modify() |
77 |
|
131 |
|
78 |
# do we have a forward zone for this IP address? |
132 |
# do we have a forward zone for this IP addresses? |
79 |
if oldip and oldip != ip: |
133 |
for address in saddresses: |
80 |
fmodule = univention.admin.modules.get('dns/forward_zone') |
134 |
for forwardobject in univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=filter_format(f'({attribute}=%s)', (address,))): |
81 |
for forwardobject in univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=filter_format('(aRecord=%s)', (oldip,))): |
|
|
82 |
forwardobject.open() |
135 |
forwardobject.open() |
83 |
forwardobject['a'].remove(oldip) |
136 |
forwardobject['a'].remove(address) |
84 |
forwardobject['a'].append(ip) |
137 |
forwardobject['a'].append(naddress) |
85 |
forwardobject.modify() |
138 |
forwardobject.modify() |
86 |
|
139 |
|
87 |
# remove old DNS reverse entries with old IP |
|
|
88 |
server = cmodule.object(None, lo, position, self.user_dn) |
89 |
server.open() |
90 |
current_ips = server['ip'] |
91 |
for entry in server['dnsEntryZoneReverse']: |
92 |
if entry[1] in current_ips: |
93 |
server['dnsEntryZoneReverse'].remove(entry) |
94 |
|
95 |
# change IP |
96 |
server['ip'] = ip |
97 |
MODULE.info(f'Change IP to {ip}') |
98 |
server.modify() |
99 |
|
100 |
# do we have a new reverse zone for this IP address? |
140 |
# do we have a new reverse zone for this IP address? |
101 |
rmodule = univention.admin.modules.get('dns/reverse_zone') |
141 |
parts = network.network_address.exploded.split(sattribute) |
102 |
parts = network.network_address.exploded.split('.') |
142 |
while parts[-1] == tattribute: |
103 |
while parts[-1] == '0': |
|
|
104 |
parts.pop() |
143 |
parts.pop() |
105 |
|
144 |
|
106 |
while parts: |
145 |
while parts: |
107 |
subnet = '.'.join(parts) |
146 |
subnet = sattribute.join(parts) |
108 |
parts.pop() |
147 |
parts.pop() |
109 |
filter = filter_format('(subnet=%s)', (subnet,)) |
148 |
reverseobject = univention.admin.modules.lookup(rmodule, None, lo, scope='sub', superordinate=None, filter=filter_format('(subnet=%s)', (subnet,))) |
110 |
reverseobject = univention.admin.modules.lookup(rmodule, None, lo, scope='sub', superordinate=None, filter=filter) |
|
|
111 |
if reverseobject: |
149 |
if reverseobject: |
112 |
server = cmodule.object(None, lo, position, self.user_dn) |
|
|
113 |
server.open() |
150 |
server.open() |
114 |
server['dnsEntryZoneReverse'].append([reverseobject[0].dn, ip]) |
151 |
server['dnsEntryZoneReverse'].append([reverseobject[0].dn, naddress]) |
115 |
server.modify() |
152 |
server.modify() |
116 |
break |
153 |
break |
117 |
|
154 |
|
118 |
# Change ucs-sso entry |
155 |
# remove old server entries with old server addresses |
119 |
# FIXME: this should be done for UCS-in-AD domains as well! |
156 |
server.open() |
120 |
ucr.load() |
157 |
for zone in ['dnsEntryZoneReverse', 'dnsEntryZoneForward']: |
121 |
sso_fqdn = ucr.get('ucs/server/sso/fqdn') |
158 |
for entry in server[zone]: |
122 |
if ucr.is_true('ucs/server/sso/autoregistraton', True): |
159 |
if entry[1] in saddresses: |
123 |
fmodule = univention.admin.modules.get('dns/forward_zone') |
160 |
server[zone].remove(entry) |
124 |
forwardobjects = univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=None) |
161 |
|
125 |
for forwardobject in forwardobjects: |
162 |
# change/append server address |
126 |
zone = forwardobject.get('zone') |
163 |
server['ip'].append(naddress) |
127 |
if not sso_fqdn.endswith(zone): |
164 |
MODULE.info(f'Change IP address {ip} for {fqdns[0]}') |
128 |
continue |
165 |
server.modify() |
129 |
sso_name = sso_fqdn[:-(len(zone) + 1)] |
166 |
|
130 |
for current_ip in current_ips: |
167 |
# cleanup any old ip addresses |
131 |
records = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', superordinate=forwardobject, filter=filter_format('(&(relativeDomainName=%s)(aRecord=%s))', (sso_name, current_ip))) |
168 |
server.open() |
132 |
for record in records: |
169 |
for entry in server['ip']: |
133 |
record.open() |
170 |
if entry in saddresses: |
134 |
if oldip in record['a']: |
171 |
server['ip'].remove(entry) |
135 |
record['a'].remove(oldip) |
172 |
server.modify() |
136 |
record['a'].append(ip) |
|
|
137 |
record.modify() |