Project

General

Profile

Bug #27246

IPAddr::InvalidAddressError on valid link-local address on Windows

Added by Martyn Smith 3 months ago. Updated 3 months ago.

Status:
Closed
Priority:
Normal
Category:
Facts
Target version:
-
Difficulty:
Triaged:
No
Bugzilla link:
Fixed in Releases:
Found in Releases:

Description

Hi

There appears to be an issue with parsing valid link-local ipv6 addresses on Azure.

This address (assigned on Windows)

Ethernet adapter Ethernet:

Connection-specific DNS Suffix  . : reddog.microsoft.com
Description . . . . . . . . . . . : Microsoft Hyper-V Network Adapter
Physical Address. . . . . . . . . : 00-22-48-07-F2-71
DHCP Enabled. . . . . . . . . . . : Yes
Autoconfiguration Enabled . . . . : Yes
Link-local IPv6 Address . . . . . : fe80::302f:51e0:1313:f50d%5(Preferred)
IPv4 Address. . . . . . . . . . . : XXX.XXX.XXX.XXX Preferred)
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Lease Obtained. . . . . . . . . . : Friday, June 28, 2019 10:06:52 AM

is read by factor correctly as:

"ipaddress6": "fe80::302f:51e0:1313:f50d%5",

and then causes an exception

2019-07-08T03:44:22 [I|app|9449499f] Import facts for 'server.domain.tribal-int.com' completed. Added: 0, Updated: 0, Deleted 0 facts
2019-07-08T03:44:22 [W|app|9449499f] Action failed
IPAddr::InvalidAddressError: invalid address
/opt/rh/rh-ruby25/root/usr/share/ruby/ipaddr.rb:649:in `in6_addr'
/opt/rh/rh-ruby25/root/usr/share/ruby/ipaddr.rb:586:in `initialize'
/usr/share/foreman/app/models/subnet.rb:299:in `new'
/usr/share/foreman/app/models/subnet.rb:299:in `subnet_for'
/usr/share/foreman/app/models/host/base.rb:488:in `set_interface'
/usr/share/foreman/app/models/host/base.rb:222:in `block in set_interfaces'
/usr/share/foreman/app/models/host/base.rb:219:in `each'
/usr/share/foreman/app/models/host/base.rb:219:in `set_interfaces'
/usr/share/foreman/app/models/host/base.rb:189:in `populate_fields_from_facts'
/usr/share/foreman/app/models/host/managed.rb:412:in `populate_fields_from_facts'
/usr/share/foreman/app/models/concerns/puppet_host_extensions.rb:3:in `populate_fields_from_facts'
/usr/share/foreman/app/models/host/base.rb:169:in `block in parse_facts'
/usr/share/foreman/app/services/foreman/telemetry_helper.rb:27:in `telemetry_duration_histogram'
/usr/share/foreman/app/models/host/base.rb:168:in `parse_facts'
/usr/share/foreman/app/models/host/base.rb:154:in `import_facts'
/opt/theforeman/tfm/root/usr/share/gems/gems/foreman_default_hostgroup-5.0.0/lib/default_hostgroup_base_host_patch.rb:13:in `import_facts'
/usr/share/foreman/app/models/host/managed.rb:326:in `import_facts'
/opt/theforeman/tfm/root/usr/share/gems/gems/foreman_default_hostgroup-5.0.0/lib/default_hostgroup_base_host_patch.rb:6:in `import_facts'
/usr/share/foreman/app/controllers/api/v2/hosts_controller.rb:306:in `facts'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/abstract_controller/base.rb:194:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal/rendering.rb:30:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:109:in `block in run_callbacks'
/usr/share/foreman/app/controllers/api/v2/base_controller.rb:163:in `disable_json_root'
/usr/share/foreman/app/controllers/concerns/foreman/controller/timezone.rb:10:in `set_timezone'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:118:in `block in run_callbacks'
/usr/share/foreman/app/models/concerns/foreman/thread_session.rb:32:in `clear_thread'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:118:in `block in run_callbacks'
/usr/share/foreman/app/controllers/concerns/foreman/controller/topbar_sweeper.rb:12:in `set_topbar_sweeper_controller'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:118:in `block in run_callbacks'
/opt/theforeman/tfm/root/usr/share/gems/gems/audited-4.7.1/lib/audited/sweeper.rb:14:in `around'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:118:in `block in run_callbacks'
/opt/theforeman/tfm/root/usr/share/gems/gems/audited-4.7.1/lib/audited/sweeper.rb:14:in `around'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:118:in `block in run_callbacks'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:136:in `run_callbacks'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/abstract_controller/callbacks.rb:41:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal/rescue.rb:22:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/notifications.rb:168:in `block in instrument'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/notifications/instrumenter.rb:23:in `instrument'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/notifications.rb:168:in `instrument'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal/instrumentation.rb:32:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal/params_wrapper.rb:256:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activerecord-5.2.1/lib/active_record/railties/controller_runtime.rb:24:in `process_action'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/abstract_controller/base.rb:134:in `process'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionview-5.2.1/lib/action_view/rendering.rb:32:in `process'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal.rb:191:in `dispatch'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_controller/metal.rb:252:in `dispatch'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/routing/route_set.rb:52:in `dispatch'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/routing/route_set.rb:34:in `serve'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/routing/mapper.rb:18:in `block in <class:Constraints>'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/routing/mapper.rb:48:in `serve'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/journey/router.rb:52:in `block in serve'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/journey/router.rb:35:in `each'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/journey/router.rb:35:in `serve'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/routing/route_set.rb:840:in `call'
/opt/theforeman/tfm/root/usr/share/gems/gems/apipie-rails-0.5.14/lib/apipie/static_dispatcher.rb:65:in `call'
/opt/theforeman/tfm/root/usr/share/gems/gems/apipie-rails-0.5.14/lib/apipie/extractor/recorder.rb:137:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/static.rb:127:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/static.rb:127:in `call'
/usr/share/foreman/lib/foreman/middleware/telemetry.rb:10:in `call'
/opt/theforeman/tfm/root/usr/share/gems/gems/apipie-rails-0.5.14/lib/apipie/middleware/checksum_in_headers.rb:27:in `call'
/usr/share/foreman/lib/foreman/middleware/catch_json_parse_errors.rb:9:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/tempfile_reaper.rb:15:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/etag.rb:25:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/conditional_get.rb:38:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/head.rb:12:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/http/content_security_policy.rb:18:in `call'
/usr/share/foreman/lib/foreman/middleware/logging_context_session.rb:22:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/session/abstract/id.rb:232:in `context'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/session/abstract/id.rb:226:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/cookies.rb:670:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/callbacks.rb:98:in `run_callbacks'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/debug_exceptions.rb:61:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/railties-5.2.1/lib/rails/rack/logger.rb:38:in `call_app'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/railties-5.2.1/lib/rails/rack/logger.rb:28:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/sprockets-rails-3.2.1/lib/sprockets/rails/quiet_assets.rb:13:in `call'
/usr/share/foreman/lib/foreman/middleware/logging_context_request.rb:11:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/method_override.rb:22:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/runtime.rb:22:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/activesupport-5.2.1/lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/executor.rb:14:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/actionpack-5.2.1/lib/action_dispatch/middleware/static.rb:127:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/sendfile.rb:111:in `call'
/opt/theforeman/tfm/root/usr/share/gems/gems/secure_headers-6.0.0/lib/secure_headers/middleware.rb:13:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/railties-5.2.1/lib/rails/engine.rb:524:in `call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/railties-5.2.1/lib/rails/railtie.rb:190:in `public_send'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/railties-5.2.1/lib/rails/railtie.rb:190:in `method_missing'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/urlmap.rb:68:in `block in call'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/urlmap.rb:53:in `each'
/opt/theforeman/tfm-ror52/root/usr/share/gems/gems/rack-2.0.6/lib/rack/urlmap.rb:53:in `call'
/usr/share/passenger/phusion_passenger/rack/thread_handler_extension.rb:74:in `process_request'
/usr/share/passenger/phusion_passenger/request_handler/thread_handler.rb:141:in `accept_and_process_next_request'
/usr/share/passenger/phusion_passenger/request_handler/thread_handler.rb:109:in `main_loop'
/usr/share/passenger/phusion_passenger/request_handler.rb:455:in `block (3 levels) in start_threads'
/opt/theforeman/tfm/root/usr/share/gems/gems/logging-2.2.2/lib/logging/diagnostic_context.rb:474:in `block in create_with_logging_context'

This appears to be caused by the regex relating to ipv6 addresses not taking into account that a valid format can contain % followed by a number as per the thread below:

https://superuser.com/questions/99746/why-is-there-a-percent-sign-in-the-ipv6-address


Related issues

Related to Foreman - Bug #26060: Fact parse error - IPAddr::InvalidAddressError: invalid addressClosed

Associated revisions

Revision 9e0afc5f (diff)
Added by Ewoud Kohl van Wijngaarden 3 months ago

Fixes #27246 - Handle device identifiers in IPs

On Windows Facter can return an IPv6 link local including the device
identifier:

fe80::302f:51e0:1313:f50d%5

However, IPAddr doesn't handle this. This patch handles this case and
cleans up the link local handling by using the underlying Ruby function
which also detects ignores IPv4 link local.

History

#1 Updated by Martyn Smith 3 months ago

  • Related to Bug #26060: Fact parse error - IPAddr::InvalidAddressError: invalid address added

#2 Updated by Martyn Smith 3 months ago

  • Category set to Facts

#3 Updated by Martyn Smith 3 months ago

Looks like it relates to the RE_IPV6ADDRLIKE_FULL and RE_IPV6ADDRLIKE_COMPRESSED regexes from upstream Ruby code in ipaddr.rb

Neither of these recognise the link-local address.

#4 Updated by Martyn Smith 3 months ago

Ok - I've a hacky workaround that works but it's a change to the upstream ipaddr.rb

Documenting it here for those interested as this breaks default_hostgroup and subnets having the VMs that are provisioned being recognised as being on the subnet when the facts are uploaded into foreman.

Update the ruby/ipaddr.rb with the 2 extra lines in the regex as highlighted below.

RE_IPV6ADDRLIKE_COMPRESSED = %r{
\A
( (?: (?: [\da-f]{1,4} : )* [\da-f]{1,4} )? )
::
( (?:
( (?: [\da-f]{1,4} : )* )
(?:
[\da-f]{1,4} |
(\d+) \. (\d+) \. (\d+) \. (\d+)
+ |
+ [\da-f]{1,4} %[\d]+
)
)? )
\z

Regards
Martyn

#5 Updated by Ewoud Kohl van Wijngaarden 3 months ago

That's not really correct because in Linux the device identifiers (which are after the % sign) are the literal device identifier, e.g. eth0, enp0s31f6 or wlp58s0.

Perhaps we should catch it and do some fallback logic. Something like this is untested, but fairly defensive in its parsing.

def parse_ip(address)
  begin
    IPAddr.new(address)
  rescue IPAddr::InvalidAddressError
    # Discard the device identifier for IPv6 link local
    raise unless address.is_a?(String) && address.include?('%')
    result = IPAddr.new(address.split('%').first)
    raise unless result.ipv6? && result.link_local?
    result
  end
end

#6 Updated by Ewoud Kohl van Wijngaarden 3 months ago

https://bugs.ruby-lang.org/issues/8464 looks like an upstream bug about this.

#7 Updated by The Foreman Bot 3 months ago

  • Assignee set to Ewoud Kohl van Wijngaarden
  • Status changed from New to Ready For Testing
  • Pull request https://github.com/theforeman/foreman/pull/6884 added

#8 Updated by Martyn Smith 3 months ago

Thanks Ewoud

I'd definitely suggest we catch it as an exception on fact upload appears to stop other processes, which run after the fact upload,to run. Subnets assignment and default_hostgroup updates are processes I'm aware of but there are possibly others as well.

I'm happy that changing the ipaddr regex is the wrong approach and accept your suggestion.

Martyn

#9 Updated by Timo Goebel 3 months ago

  • Fixed in Releases 1.23.0 added

#10 Updated by Ewoud Kohl van Wijngaarden 3 months ago

  • Status changed from Ready For Testing to Closed

Also available in: Atom PDF