1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "alloc-util.h"
6 #include "conf-parser.h"
7 #include "firewall-util.h"
8 #include "memory-util.h"
9 #include "missing_network.h"
10 #include "netlink-util.h"
11 #include "networkd-address.h"
12 #include "networkd-manager.h"
13 #include "parse-util.h"
15 #include "socket-util.h"
16 #include "string-util.h"
20 #define ADDRESSES_PER_LINK_MAX 2048U
21 #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
23 int address_new(Address
**ret
) {
24 _cleanup_(address_freep
) Address
*address
= NULL
;
26 address
= new(Address
, 1);
30 *address
= (Address
) {
32 .scope
= RT_SCOPE_UNIVERSE
,
33 .cinfo
.ifa_prefered
= CACHE_INFO_INFINITY_LIFE_TIME
,
34 .cinfo
.ifa_valid
= CACHE_INFO_INFINITY_LIFE_TIME
,
37 *ret
= TAKE_PTR(address
);
42 static int address_new_static(Network
*network
, const char *filename
, unsigned section_line
, Address
**ret
) {
43 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
44 _cleanup_(address_freep
) Address
*address
= NULL
;
49 assert(!!filename
== (section_line
> 0));
52 r
= network_config_section_new(filename
, section_line
, &n
);
56 address
= hashmap_get(network
->addresses_by_section
, n
);
58 *ret
= TAKE_PTR(address
);
64 if (network
->n_static_addresses
>= STATIC_ADDRESSES_PER_NETWORK_MAX
)
67 r
= address_new(&address
);
71 address
->network
= network
;
72 LIST_APPEND(addresses
, network
->static_addresses
, address
);
73 network
->n_static_addresses
++;
76 address
->section
= TAKE_PTR(n
);
78 r
= hashmap_ensure_allocated(&network
->addresses_by_section
, &network_config_hash_ops
);
82 r
= hashmap_put(network
->addresses_by_section
, address
->section
, address
);
87 *ret
= TAKE_PTR(address
);
92 void address_free(Address
*address
) {
96 if (address
->network
) {
97 LIST_REMOVE(addresses
, address
->network
->static_addresses
, address
);
98 assert(address
->network
->n_static_addresses
> 0);
99 address
->network
->n_static_addresses
--;
101 if (address
->section
)
102 hashmap_remove(address
->network
->addresses_by_section
, address
->section
);
106 set_remove(address
->link
->addresses
, address
);
107 set_remove(address
->link
->addresses_foreign
, address
);
109 if (in_addr_equal(AF_INET6
, &address
->in_addr
, (const union in_addr_union
*) &address
->link
->ipv6ll_address
))
110 memzero(&address
->link
->ipv6ll_address
, sizeof(struct in6_addr
));
113 network_config_section_free(address
->section
);
114 free(address
->label
);
118 static void address_hash_func(const Address
*a
, struct siphash
*state
) {
121 siphash24_compress(&a
->family
, sizeof(a
->family
), state
);
125 siphash24_compress(&a
->prefixlen
, sizeof(a
->prefixlen
), state
);
128 if (a
->prefixlen
!= 0) {
131 if (a
->in_addr_peer
.in
.s_addr
!= 0)
132 prefix
= be32toh(a
->in_addr_peer
.in
.s_addr
) >> (32 - a
->prefixlen
);
134 prefix
= be32toh(a
->in_addr
.in
.s_addr
) >> (32 - a
->prefixlen
);
136 siphash24_compress(&prefix
, sizeof(prefix
), state
);
142 siphash24_compress(&a
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
), state
);
146 /* treat any other address family as AF_UNSPEC */
151 static int address_compare_func(const Address
*a1
, const Address
*a2
) {
154 r
= CMP(a1
->family
, a2
->family
);
158 switch (a1
->family
) {
159 /* use the same notion of equality as the kernel does */
161 r
= CMP(a1
->prefixlen
, a2
->prefixlen
);
165 /* compare the peer prefixes */
166 if (a1
->prefixlen
!= 0) {
167 /* make sure we don't try to shift by 32.
168 * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
171 if (a1
->in_addr_peer
.in
.s_addr
!= 0)
172 b1
= be32toh(a1
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
174 b1
= be32toh(a1
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
176 if (a2
->in_addr_peer
.in
.s_addr
!= 0)
177 b2
= be32toh(a2
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
179 b2
= be32toh(a2
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
188 return memcmp(&a1
->in_addr
, &a2
->in_addr
, FAMILY_ADDRESS_SIZE(a1
->family
));
190 /* treat any other address family as AF_UNSPEC */
195 DEFINE_PRIVATE_HASH_OPS(address_hash_ops
, Address
, address_hash_func
, address_compare_func
);
197 bool address_equal(Address
*a1
, Address
*a2
) {
204 return address_compare_func(a1
, a2
) == 0;
207 static int address_establish(Address
*address
, Link
*link
) {
214 masq
= link
->network
&&
215 link
->network
->ip_masquerade
&&
216 address
->family
== AF_INET
&&
217 address
->scope
< RT_SCOPE_LINK
;
219 /* Add firewall entry if this is requested */
220 if (address
->ip_masquerade_done
!= masq
) {
221 union in_addr_union masked
= address
->in_addr
;
222 in_addr_mask(address
->family
, &masked
, address
->prefixlen
);
224 r
= fw_add_masquerade(masq
, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
228 address
->ip_masquerade_done
= masq
;
234 static int address_add_internal(Link
*link
, Set
**addresses
,
236 const union in_addr_union
*in_addr
,
237 unsigned char prefixlen
,
239 _cleanup_(address_freep
) Address
*address
= NULL
;
246 r
= address_new(&address
);
250 address
->family
= family
;
251 address
->in_addr
= *in_addr
;
252 address
->prefixlen
= prefixlen
;
253 /* Consider address tentative until we get the real flags from the kernel */
254 address
->flags
= IFA_F_TENTATIVE
;
256 r
= set_ensure_allocated(addresses
, &address_hash_ops
);
260 r
= set_put(*addresses
, address
);
266 address
->link
= link
;
276 int address_add_foreign(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
277 return address_add_internal(link
, &link
->addresses_foreign
, family
, in_addr
, prefixlen
, ret
);
280 int address_add(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
284 r
= address_get(link
, family
, in_addr
, prefixlen
, &address
);
286 /* Address does not exist, create a new one */
287 r
= address_add_internal(link
, &link
->addresses
, family
, in_addr
, prefixlen
, &address
);
291 /* Take over a foreign address */
292 r
= set_ensure_allocated(&link
->addresses
, &address_hash_ops
);
296 r
= set_put(link
->addresses
, address
);
300 set_remove(link
->addresses_foreign
, address
);
302 /* Already exists, do nothing */
313 static int address_release(Address
*address
) {
317 assert(address
->link
);
319 /* Remove masquerading firewall entry if it was added */
320 if (address
->ip_masquerade_done
) {
321 union in_addr_union masked
= address
->in_addr
;
322 in_addr_mask(address
->family
, &masked
, address
->prefixlen
);
324 r
= fw_add_masquerade(false, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
328 address
->ip_masquerade_done
= false;
338 const struct ifa_cacheinfo
*cinfo
) {
345 assert_return(address
->link
, 1);
347 if (IN_SET(address
->link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
350 ready
= address_is_ready(address
);
352 address
->flags
= flags
;
353 address
->scope
= scope
;
354 address
->cinfo
= *cinfo
;
356 link_update_operstate(address
->link
, true);
357 link_check_ready(address
->link
);
360 address_is_ready(address
) &&
361 address
->family
== AF_INET6
&&
362 in_addr_is_link_local(AF_INET6
, &address
->in_addr
) > 0 &&
363 in_addr_is_null(AF_INET6
, (const union in_addr_union
*) &address
->link
->ipv6ll_address
) > 0) {
365 r
= link_ipv6ll_gained(address
->link
, &address
->in_addr
.in6
);
373 int address_drop(Address
*address
) {
380 ready
= address_is_ready(address
);
381 link
= address
->link
;
383 r
= address_release(address
);
385 log_link_warning_errno(link
, r
, "Failed to disable IP masquerading, ignoring: %m");
387 address_free(address
);
389 link_update_operstate(link
, true);
392 link_check_ready(link
);
397 int address_get(Link
*link
,
399 const union in_addr_union
*in_addr
,
400 unsigned char prefixlen
,
403 Address address
, *existing
;
408 address
= (Address
) {
411 .prefixlen
= prefixlen
,
414 existing
= set_get(link
->addresses
, &address
);
421 existing
= set_get(link
->addresses_foreign
, &address
);
431 static int address_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
436 assert(link
->ifname
);
438 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
441 r
= sd_netlink_message_get_errno(m
);
442 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
443 log_link_warning_errno(link
, r
, "Could not drop address: %m");
451 link_netlink_message_handler_t callback
) {
453 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
457 assert(IN_SET(address
->family
, AF_INET
, AF_INET6
));
459 assert(link
->ifindex
> 0);
460 assert(link
->manager
);
461 assert(link
->manager
->rtnl
);
464 _cleanup_free_
char *b
= NULL
;
466 (void) in_addr_to_string(address
->family
, &address
->in_addr
, &b
);
467 log_link_debug(link
, "Removing address %s", strna(b
));
470 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_DELADDR
,
471 link
->ifindex
, address
->family
);
473 return log_link_error_errno(link
, r
, "Could not allocate RTM_DELADDR message: %m");
475 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
477 return log_link_error_errno(link
, r
, "Could not set prefixlen: %m");
479 r
= netlink_message_append_in_addr_union(req
, IFA_LOCAL
, address
->family
, &address
->in_addr
);
481 return log_link_error_errno(link
, r
, "Could not append IFA_LOCAL attribute: %m");
483 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
,
484 callback
?: address_remove_handler
,
485 link_netlink_destroy_callback
, link
);
487 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
494 static int address_acquire(Link
*link
, Address
*original
, Address
**ret
) {
495 union in_addr_union in_addr
= IN_ADDR_NULL
;
496 struct in_addr broadcast
= {};
497 _cleanup_(address_freep
) Address
*na
= NULL
;
504 /* Something useful was configured? just use it */
505 r
= in_addr_is_null(original
->family
, &original
->in_addr
);
509 /* The address is configured to be 0.0.0.0 or [::] by the user?
510 * Then let's acquire something more useful from the pool. */
511 r
= manager_address_pool_acquire(link
->manager
, original
->family
, original
->prefixlen
, &in_addr
);
517 if (original
->family
== AF_INET
) {
518 /* Pick first address in range for ourselves ... */
519 in_addr
.in
.s_addr
= in_addr
.in
.s_addr
| htobe32(1);
521 /* .. and use last as broadcast address */
522 if (original
->prefixlen
> 30)
523 broadcast
.s_addr
= 0;
525 broadcast
.s_addr
= in_addr
.in
.s_addr
| htobe32(0xFFFFFFFFUL
>> original
->prefixlen
);
526 } else if (original
->family
== AF_INET6
)
527 in_addr
.in6
.s6_addr
[15] |= 1;
529 r
= address_new(&na
);
533 na
->family
= original
->family
;
534 na
->prefixlen
= original
->prefixlen
;
535 na
->scope
= original
->scope
;
536 na
->cinfo
= original
->cinfo
;
538 if (original
->label
) {
539 na
->label
= strdup(original
->label
);
544 na
->broadcast
= broadcast
;
545 na
->in_addr
= in_addr
;
547 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
554 int address_configure(
557 link_netlink_message_handler_t callback
,
560 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
564 assert(IN_SET(address
->family
, AF_INET
, AF_INET6
));
566 assert(link
->ifindex
> 0);
567 assert(link
->manager
);
568 assert(link
->manager
->rtnl
);
571 /* If this is a new address, then refuse adding more than the limit */
572 if (address_get(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
) <= 0 &&
573 set_size(link
->addresses
) >= ADDRESSES_PER_LINK_MAX
)
574 return log_link_error_errno(link
, SYNTHETIC_ERRNO(E2BIG
),
575 "Too many addresses are configured, refusing: %m");
577 r
= address_acquire(link
, address
, &address
);
579 return log_link_error_errno(link
, r
, "Failed to acquire an address from pool: %m");
582 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
583 link
->ifindex
, address
->family
);
585 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
586 link
->ifindex
, address
->family
);
588 return log_link_error_errno(link
, r
, "Could not allocate RTM_NEWADDR message: %m");
590 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
592 return log_link_error_errno(link
, r
, "Could not set prefixlen: %m");
594 address
->flags
|= IFA_F_PERMANENT
;
596 if (address
->home_address
)
597 address
->flags
|= IFA_F_HOMEADDRESS
;
599 if (address
->duplicate_address_detection
)
600 address
->flags
|= IFA_F_NODAD
;
602 if (address
->manage_temporary_address
)
603 address
->flags
|= IFA_F_MANAGETEMPADDR
;
605 if (address
->prefix_route
)
606 address
->flags
|= IFA_F_NOPREFIXROUTE
;
608 if (address
->autojoin
)
609 address
->flags
|= IFA_F_MCAUTOJOIN
;
611 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
613 return log_link_error_errno(link
, r
, "Could not set flags: %m");
615 if (address
->flags
& ~0xff) {
616 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
618 return log_link_error_errno(link
, r
, "Could not set extended flags: %m");
621 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
623 return log_link_error_errno(link
, r
, "Could not set scope: %m");
625 r
= netlink_message_append_in_addr_union(req
, IFA_LOCAL
, address
->family
, &address
->in_addr
);
627 return log_link_error_errno(link
, r
, "Could not append IFA_LOCAL attribute: %m");
629 if (in_addr_is_null(address
->family
, &address
->in_addr_peer
) == 0) {
630 r
= netlink_message_append_in_addr_union(req
, IFA_ADDRESS
, address
->family
, &address
->in_addr_peer
);
632 return log_link_error_errno(link
, r
, "Could not append IFA_ADDRESS attribute: %m");
633 } else if (address
->family
== AF_INET
&& address
->prefixlen
<= 30) {
634 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
636 return log_link_error_errno(link
, r
, "Could not append IFA_BROADCAST attribute: %m");
639 if (address
->label
) {
640 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
642 return log_link_error_errno(link
, r
, "Could not append IFA_LABEL attribute: %m");
645 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
, &address
->cinfo
);
647 return log_link_error_errno(link
, r
, "Could not append IFA_CACHEINFO attribute: %m");
649 r
= address_establish(address
, link
);
651 log_link_warning_errno(link
, r
, "Could not enable IP masquerading, ignoring: %m");
653 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
, link_netlink_destroy_callback
, link
);
655 address_release(address
);
656 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
661 if (address
->family
== AF_INET6
&& !in_addr_is_null(address
->family
, &address
->in_addr_peer
))
662 r
= address_add(link
, address
->family
, &address
->in_addr_peer
, address
->prefixlen
, NULL
);
664 r
= address_add(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
);
666 address_release(address
);
667 return log_link_error_errno(link
, r
, "Could not add address: %m");
673 int config_parse_broadcast(
675 const char *filename
,
678 unsigned section_line
,
685 Network
*network
= userdata
;
686 _cleanup_(address_free_or_set_invalidp
) Address
*n
= NULL
;
695 r
= address_new_static(network
, filename
, section_line
, &n
);
699 if (n
->family
== AF_INET6
) {
700 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
701 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue
);
705 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
707 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
708 "Broadcast is invalid, ignoring assignment: %s", rvalue
);
718 int config_parse_address(const char *unit
,
719 const char *filename
,
722 unsigned section_line
,
729 Network
*network
= userdata
;
730 _cleanup_(address_free_or_set_invalidp
) Address
*n
= NULL
;
731 union in_addr_union buffer
;
732 unsigned char prefixlen
;
741 if (streq(section
, "Network")) {
742 /* we are not in an Address section, so treat
743 * this as the special '0' section */
744 r
= address_new_static(network
, NULL
, 0, &n
);
746 r
= address_new_static(network
, filename
, section_line
, &n
);
751 /* Address=address/prefixlen */
752 r
= in_addr_prefix_from_string_auto_internal(rvalue
, PREFIXLEN_REFUSE
, &f
, &buffer
, &prefixlen
);
754 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
755 "An address '%s' is specified without prefix length. "
756 "The behavior of parsing addresses without prefix length will be changed in the future release. "
757 "Please specify prefix length explicitly.", rvalue
);
759 r
= in_addr_prefix_from_string_auto_internal(rvalue
, PREFIXLEN_LEGACY
, &f
, &buffer
, &prefixlen
);
762 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid address '%s', ignoring assignment: %m", rvalue
);
766 if (n
->family
!= AF_UNSPEC
&& f
!= n
->family
) {
767 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address is incompatible, ignoring assignment: %s", rvalue
);
771 if (in_addr_is_null(f
, &buffer
)) {
772 /* Will use address from address pool. Note that for ipv6 case, prefix of the address
773 * pool is 8, but 40 bit is used by the global ID and 16 bit by the subnet ID. So,
774 * let's limit the prefix length to 64 or larger. See RFC4193. */
775 if ((f
== AF_INET
&& prefixlen
< 8) ||
776 (f
== AF_INET6
&& prefixlen
< 64)) {
777 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
778 "Null address with invalid prefixlen='%u', ignoring assignment: %s",
785 n
->prefixlen
= prefixlen
;
787 if (streq(lvalue
, "Address"))
790 n
->in_addr_peer
= buffer
;
792 if (n
->family
== AF_INET
&& n
->broadcast
.s_addr
== 0 && n
->prefixlen
<= 30)
793 n
->broadcast
.s_addr
= n
->in_addr
.in
.s_addr
| htobe32(0xfffffffflu
>> n
->prefixlen
);
800 int config_parse_label(
802 const char *filename
,
805 unsigned section_line
,
812 _cleanup_(address_free_or_set_invalidp
) Address
*n
= NULL
;
813 Network
*network
= userdata
;
822 r
= address_new_static(network
, filename
, section_line
, &n
);
826 if (!address_label_valid(rvalue
)) {
827 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
828 "Interface label is too long or invalid, ignoring assignment: %s", rvalue
);
832 r
= free_and_strdup(&n
->label
, rvalue
);
840 int config_parse_lifetime(const char *unit
,
841 const char *filename
,
844 unsigned section_line
,
850 Network
*network
= userdata
;
851 _cleanup_(address_free_or_set_invalidp
) Address
*n
= NULL
;
861 r
= address_new_static(network
, filename
, section_line
, &n
);
865 /* We accept only "forever", "infinity", or "0". */
866 if (STR_IN_SET(rvalue
, "forever", "infinity"))
867 k
= CACHE_INFO_INFINITY_LIFE_TIME
;
868 else if (streq(rvalue
, "0"))
871 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
872 "Invalid PreferredLifetime= value, ignoring: %s", rvalue
);
876 n
->cinfo
.ifa_prefered
= k
;
882 int config_parse_address_flags(const char *unit
,
883 const char *filename
,
886 unsigned section_line
,
892 Network
*network
= userdata
;
893 _cleanup_(address_free_or_set_invalidp
) Address
*n
= NULL
;
902 r
= address_new_static(network
, filename
, section_line
, &n
);
906 r
= parse_boolean(rvalue
);
908 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
909 "Failed to parse address flag, ignoring: %s", rvalue
);
913 if (streq(lvalue
, "HomeAddress"))
915 else if (streq(lvalue
, "DuplicateAddressDetection"))
916 n
->duplicate_address_detection
= r
;
917 else if (streq(lvalue
, "ManageTemporaryAddress"))
918 n
->manage_temporary_address
= r
;
919 else if (streq(lvalue
, "PrefixRoute"))
921 else if (streq(lvalue
, "AutoJoin"))
924 assert_not_reached("Invalid address flag type.");
930 int config_parse_address_scope(const char *unit
,
931 const char *filename
,
934 unsigned section_line
,
940 Network
*network
= userdata
;
941 _cleanup_(address_free_or_set_invalidp
) Address
*n
= NULL
;
950 r
= address_new_static(network
, filename
, section_line
, &n
);
954 if (streq(rvalue
, "host"))
955 n
->scope
= RT_SCOPE_HOST
;
956 else if (streq(rvalue
, "link"))
957 n
->scope
= RT_SCOPE_LINK
;
958 else if (streq(rvalue
, "global"))
959 n
->scope
= RT_SCOPE_UNIVERSE
;
961 r
= safe_atou8(rvalue
, &n
->scope
);
963 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
964 "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue
);
973 bool address_is_ready(const Address
*a
) {
976 return !(a
->flags
& IFA_F_TENTATIVE
);
979 int address_section_verify(Address
*address
) {
980 if (section_is_invalid(address
->section
))
983 if (address
->family
== AF_UNSPEC
) {
984 assert(address
->section
);
986 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
987 "%s: Address section without Address= field configured. "
988 "Ignoring [Address] section from line %u.",
989 address
->section
->filename
, address
->section
->line
);