
    >Tf]                        d dl Z d dlmZ d dlmZ d dlmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZ d d	lmZ d d
lmZ d dlT d dlT d dlmZmZ d dlmZ d dlmZ d dlmZ d dlm Z  d dl!m"Z" d dl#m$Z$m%Z% d dl&m'Z' dZ( G d d          Z) G d de$          Z* G d de'e)e%          Z+ G d de$          Z, G d de'e)e%          Z- G d d e'e%          Z. G d! d"e'e%          Z/dS )#    N)GenericForeignKey)ValidationError)models)F)Cast)reverse)cached_property)gettext_lazy)
ObjectType)*)IPNetworkFieldIPAddressField)Host)IPAddressManager)PrefixQuerySet)DNSValidator)
get_config)OrganizationalModelPrimaryModel)ContactsMixin)	Aggregate	IPAddressIPRangePrefixRIRRolec                       e Zd Zd Zd ZdS )GetAvailablePrefixesMixinc                    dt          | j                  i}t          | d          r
| j        |d<   t	          j        j        di |                    dd          }t          j	        | j                  t          j	        |          z
  S )z\
        Return all available prefixes within this Aggregate or Prefix as an IPSet.
        prefix__net_containedvrfprefixTflat )
strr"   hasattrr!   r   objectsfiltervalues_listnetaddrIPSet)selfparamschild_prefixess      3/var/www/html/netbox-4.1.3/netbox/ipam/models/ip.pyget_available_prefixesz0GetAvailablePrefixesMixin.get_available_prefixes#   s    
 $S%5%5
 4 	% HF5M.8888DDXTXDYY}T[))GM.,I,III    c                 f    |                                  }|sdS |                                d         S )zV
        Return the first available child prefix within the prefix (or None).
        Nr   )r1   
iter_cidrs)r-   available_prefixess     r0   get_first_available_prefixz4GetAvailablePrefixesMixin.get_first_available_prefix0   s:     "88::! 	4!,,..q11r2   N)__name__
__module____qualname__r1   r6   r%   r2   r0   r   r   !   s5        J J J2 2 2 2 2r2   r   c                   |    e Zd ZdZ ej        d ed           ed                    Z G d d          Zd Z	d	S )
r   z
    A Regional Internet Registry (RIR) is responsible for the allocation of a large portion of the global IP address
    space. This can be an organization like ARIN or RIPE, or a governing standard such as RFC 1918.
    Fprivatez2IP space managed by this RIR is considered private)defaultverbose_name	help_textc                   >    e Zd ZdZ ed          Z ed          ZdS )RIR.Metanamer   RIRsNr7   r8   r9   ordering_r=   verbose_name_pluralr%   r2   r0   Metar@   E   s0        qxxaiir2   rH   c                 0    t          d| j        g          S )Nzipam:rirargsr   pkr-   s    r0   get_absolute_urlzRIR.get_absolute_urlJ   s    z	2222r2   N)
r7   r8   r9   __doc__r   BooleanFieldrF   
is_privaterH   rO   r%   r2   r0   r   r   :   s          %$Qy\\!HII  J( ( ( ( ( ( ( (
3 3 3 3 3r2   r   c            	       `    e Zd ZdZ e ed                    Z ej        dej	        d ed           ed                    Z
 ej        d	ej	        dd
d
          Z ej         ed          d
d
          ZdZdZ G d d          Zd Zd Z fdZed             Zd Zd Z xZS )r   z
    An aggregate exists at the root level of the IP address space hierarchy in NetBox. Aggregates are used to organize
    the hierarchy and track the overall utilization of available address space. Each Aggregate is assigned to a RIR.
    zIPv4 or IPv6 network)r>   ipam.RIR
aggregatesr   z8Regional Internet Registry responsible for this IP space)to	on_deleterelated_namer=   r>   tenancy.TenantTrV   rW   rX   blanknullz
date added)r=   r[   r\   )rirtenant
date_addeddescription)rT   c                   >    e Zd ZdZ ed          Z ed          ZdS )Aggregate.Meta)r"   rM   	aggregaterU   NrD   r%   r2   r0   rH   rb   q   s0        #q~~aoor2   rH   c                 *    t          | j                  S Nr&   r"   rN   s    r0   __str__zAggregate.__str__v       4;r2   c                 0    t          d| j        g          S )Nzipam:aggregaterJ   rL   rN   s    r0   rO   zAggregate.get_absolute_urly       'twi8888r2   c                    t                                                       | j        rV| j        j        dk    rt	          dt          d          i          t          j                            t          | j                            }| j
        r|                    | j
                  }|r>t	          dt          d                              | j        |d                   i          t          j                            t          | j                            }| j
        r|                    | j
                  }|r@t	          dt          d	                              | j        |d                   i          d S d S )
Nr   r"   z%Cannot create aggregate with /0 mask.)prefix__net_contains_or_equalsrM   z^Aggregates cannot overlap. {prefix} is already covered by an existing aggregate ({aggregate}).)r"   rc   r    zXPrefixes cannot overlap aggregates. {prefix} covers an existing aggregate ({aggregate}).)supercleanr"   	prefixlenr   rF   r   r(   r)   r&   rM   excludeformat)r-   covering_aggregatescovered_aggregates	__class__s      r0   rp   zAggregate.clean|   s   ; $	 {$))%a GHH'   
 #,"3":":/24;/?/? #; # # w N&9&A&ATW&A&M&M#" %ax f#{"5a"8   '    "+!2!9!9PSTXT_P`P`!9!a!aw L%7%?%?47%?%K%K"! %ar f#{"4Q"7   '   ;$	 $	8 r2   c                 ,    | j         r| j         j        S d S re   r"   versionrN   s    r0   familyzAggregate.family   s    ; 	';&&tr2   c                 f    t           j                            t          | j                            S )z;
        Return all Prefixes within this Aggregate
        rn   )r   r(   r)   r&   r"   rN   s    r0   get_child_prefixeszAggregate.get_child_prefixes   s'     ~$$3t{;K;K$LLLr2   c                 
   t           j                            t          | j                            }t          j        d |D                       }t          |j                  | j        j        z  dz  }t          |d          S )zb
        Determine the prefix utilization of the aggregate and return it as a percentage.
        )prefix__net_contained_or_equalc                     g | ]	}|j         
S r%   r"   .0ps     r0   
<listcomp>z-Aggregate.get_utilization.<locals>.<listcomp>   s    'C'C'CQ'C'C'Cr2   d   )
r   r(   r)   r&   r"   r+   r,   floatsizemin)r-   querysetr/   utilizations       r0   get_utilizationzAggregate.get_utilization   ss     >((DKHXHX(YY 'C'C('C'C'CDDN/004;3CCcI;$$$r2   )r7   r8   r9   rP   r   rF   r"   r   
ForeignKeyPROTECTr]   r^   	DateFieldr_   clone_fieldsprerequisite_modelsrH   rg   rO   rp   propertyrz   r|   r   __classcell__rv   s   @r0   r   r   N   s         ^!*++  F &
.!QuXX!NOO  C V.!  F "!Q|__  JL. . . . . . . .
     9 9 9' ' ' ' 'R   X
M M M% % % % % % %r2   r   c                   n    e Zd ZdZ ej         ed          d          Z G d d          Zd Z	d Z
d	S )
r   z
    A Role represents the functional role of a Prefix or VLAN; for example, "Customer," "Infrastructure," or
    "Management."
    weighti  )r=   r<   c                   >    e Zd ZdZ ed          Z ed          ZdS )	Role.Meta)r   rB   rolerolesNrD   r%   r2   r0   rH   r      s0        %qyyajjr2   rH   c                     | j         S re   rA   rN   s    r0   rg   zRole.__str__   
    yr2   c                 0    t          d| j        g          S )Nz	ipam:rolerJ   rL   rN   s    r0   rO   zRole.get_absolute_url   s    {$'3333r2   N)r7   r8   r9   rP   r   PositiveSmallIntegerFieldrF   r   rH   rg   rO   r%   r2   r0   r   r      s          .V-Qx[[  F
) ) ) ) ) ) ) )
  4 4 4 4 4r2   r   c            
           e Zd ZdZ e ed           ed                    Z ej        dej	        ddd          Z
 ej        d	ej	        ddd ed
                    Z ej        dej	        ddd          Z ej        dej	        ddd          Z ej        deej         ed           ed                    Z ej        dej        ddd ed                    Z ej         ed          d ed                    Z ej         ed          d ed                    Z ej        dd          Z ej        dd          Z ej                    ZdZ G d d          Z fd Z d! Z!d" Z" fd#Z# fd$Z$e%d%             Z&e%d&             Z'e%d'             Z(e%d(             Z)d) Z* e%e**          Z+d+ Z,d5d,Z-d5d-Z.d. Z/d/ Z0d0 Z1d1 Z2d2 Z3d3 Z4d4 Z5 xZ6S )6r   a  
    A Prefix represents an IPv4 or IPv6 network, including mask length. Prefixes can optionally be assigned to Sites and
    VRFs. A Prefix must be assigned a status and may optionally be assigned a used-define Role. A Prefix can also be
    assigned to a VLAN where appropriate.
    r"   zIPv4 or IPv6 network with maskr=   r>   z	dcim.SiteprefixesTrZ   ipam.VRFVRFrV   rW   rX   r[   r\   r=   rY   z	ipam.VLAN2   statusz!Operational status of this prefix)
max_lengthchoicesr<   r=   r>   	ipam.Rolez#The primary function of this prefixrV   rW   rX   r[   r\   r>   z	is a poolFz9All IP addresses within this prefix are considered usabler=   r<   r>   mark utilizedTreat as fully utilizedr   )r<   editable)	siter!   r^   vlanr   r   is_poolmark_utilizedr`   c                   ~    e Zd Z ed                              d          ddfZ ed          Z ed          ZdS )Prefix.Metar!   Tnulls_firstr"   rM   r   N	r7   r8   r9   r   ascrE   rF   r=   rG   r%   r2   r0   rH   r   #  sM        AeHHLLTL22HdCq{{a
mmr2   rH   c                      t                      j        |i | | j                            d          | _        | j                            d          | _        d S )Nr"   vrf_id)ro   __init____dict__get_prefix_vrf_idr-   rK   kwargsrv   s      r0   r   zPrefix.__init__(  sS    $)&))) }((22}((22r2   c                 *    t          | j                  S re   rf   rN   s    r0   rg   zPrefix.__str__/  rh   r2   c                 0    t          d| j        g          S )Nzipam:prefixrJ   rL   rN   s    r0   rO   zPrefix.get_absolute_url2  s    }DG95555r2   c                 J   t                                                       | j        r| j        j        dk    rt	          dt          d          i          | j        t                      j        s| j        r| j        j	        r| 
                                }|r| j        r(t          d                              | j                  nt          d          }t	          dt          d                              ||                                          i          d S d S d S d S )	Nr   r"   z"Cannot create prefix with /0 mask.	VRF {vrf}r!   global tablez+Duplicate prefix found in {table}: {prefix})tabler"   )ro   rp   r"   rq   r   rF   r!   r   ENFORCE_GLOBAL_UNIQUEenforce_uniqueget_duplicatesrs   first)r-   duplicate_prefixesr   rv   s      r0   rp   zPrefix.clean5  s;   ; 	 {$))%a DEE'   
  Z\\%G TX Z^ZbZq %)%8%8%:%:"% CG8bAkNN11dh1???QRSaQbQbE) !$Q"R"R"Y"Y"'#5#;#;#=#= #Z # #+   	 	  !   r2   c                     t          | j        t          j                  r| j        j        | _         t                      j        |i | d S re   )
isinstancer"   r+   	IPNetworkcidrro   saver   s      r0   r   zPrefix.saveL  sI    dk7#455 	+ +*DKd%f%%%%%r2   c                 ,    | j         r| j         j        nd S re   rx   rN   s    r0   rz   zPrefix.familyU  s    &*k;t{""t;r2   c                 ,    | j         r| j         j        nd S re   r"   rq   rN   s    r0   mask_lengthzPrefix.mask_lengthY  s    (,=t{$$=r2   c                     | j         S re   )_depthrN   s    r0   depthzPrefix.depth]  s
    {r2   c                     | j         S re   )	_childrenrN   s    r0   childrenzPrefix.childrena  s
    ~r2   c                 0    | j         || j         _        dS dS z
        Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
        e.g. for bulk editing.
        Nr   r-   values     r0   _set_prefix_lengthzPrefix._set_prefix_lengthe  s$    
 ;"$)DK!!! #"r2   fsetc                 J    t           j                            | j                  S re   )PrefixStatusChoicescolorsr   r   rN   s    r0   get_status_colorzPrefix.get_status_colorn  s    ")--dk:::r2   c                 \    |rdnd}t          j        j        di d| j        d| | j        iS )zB
        Return all containing Prefixes in the hierarchy.
        net_contains_or_equalsnet_containsr!   prefix__r%   r   r(   r)   r!   r"   r-   include_selflookups      r0   get_parentszPrefix.get_parentsq  sP     .:M))~~$  48v(
   	r2   c                 \    |rdnd}t          j        j        di d| j        d| | j        iS )z?
        Return all covered Prefixes in the hierarchy.
        net_contained_or_equalnet_containedr!   r   r%   r   r   s      r0   get_childrenzPrefix.get_children{  sP     .:N))~$  48v(
   	r2   c                     t           j                            | j        t	          | j                                                | j                  S )N)r!   r"   rm   )r   r(   r)   r!   r&   r"   rr   rM   rN   s    r0   r   zPrefix.get_duplicates  s>    ~$$#dk:J:J$KKSSW[W^S___r2   c                    | j         G| j        t          j        k    r2t          j                            t          | j                            S t          j                            t          | j                  | j                   S )z
        Return all Prefixes within this Prefix and VRF. If this Prefix is a container in the global table, return child
        Prefixes belonging to any VRF.
        Nrn   r    r!   )	r!   r   r   STATUS_CONTAINERr   r(   r)   r&   r"   rN   s    r0   r|   zPrefix.get_child_prefixes  sh    
 8/B/S S S>((s4;?O?O(PPP>((s4;?O?OUYU](^^^r2   c                     t           j                            | j        t	          | j                  t	          | j                            S )zA
        Return all IPRanges within this Prefix and VRF.
        )r!   !start_address__net_host_containedend_address__net_host_contained)r   r(   r)   r!   r&   r"   rN   s    r0   get_child_rangeszPrefix.get_child_ranges  sB     %%.1$+.>.>,/,<,< & 
 
 	
r2   c                    | j         G| j        t          j        k    r2t          j                            t          | j                            S t          j                            t          | j                  | j                   S )z
        Return all IPAddresses within this Prefix and VRF. If this Prefix is a container in the global table, return
        child IPAddresses belonging to any VRF.
        N)address__net_host_contained)r   r!   )	r!   r   r   r   r   r(   r)   r&   r"   rN   s    r0   get_child_ipszPrefix.get_child_ips  sj    
 8/B/S S S$++DKHXHX+YYY$++DKHXHX^b^f+gggr2   c                    | j         rt          j                    S t          j        | j                  }t          j        d |                                 D                       }g }|                                 D ]}|                    |j                   ||z
  t          j        |          z
  }| j        dk    r| j        j	        dk    s"| j
        s| j        dk    r| j        j	        dk    r|S | j        dk    rR|t          j        t          j        | j        j                  t          j        | j        j                  g          z  }n4|t          j        t          j        | j        j                  g          z  }|S )zJ
        Return all available IPs within this prefix as an IPSet.
        c                 &    g | ]}|j         j        S r%   addressipr   r  s     r0   r   z,Prefix.get_available_ips.<locals>.<listcomp>      "P"P"PR2:="P"P"Pr2               )r   r+   r,   r"   r   r   appendrangerz   rq   r   r   r   last)r-   r"   	child_ipschild_rangesiprangeavailable_ipss         r0   get_available_ipszPrefix.get_available_ips  s     	#=??"t{++M"P"P4;M;M;O;O"P"P"PQQ	,,.. 	/ 	/G....*W]<-H-HH K1!6#!=!=$,!=SWS^bcScSchlhsh}  BD  iD  iD  ;!W]!$+"344!$+"233,   MM W]G,=dk>O,P,P+QRRRMr2   c                     |                                  }|sdS d                    t          |                                          | j        j                  S )zL
        Return the first available IP within the prefix (or None).
        N{}/{})r  rs   next__iter__r"   rq   r-   r  s     r0   get_first_available_ipzPrefix.get_first_available_ip  sO     ..00 	4~~d=#9#9#;#;<<dk>STTTr2   c                    | j         rdS | j        t          j        k    r{t          j                            t          | j                  | j	                  }t          j        d |D                       }t          |j                  | j        j        z  dz  }nt          j        d |                                 D             d |                                 D             z             }| j        j        }| j        j        dk    r| j        j        dk     r| j        s|dz  }t          |j                  |z  dz  }t'          |d          S )	z
        Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of
        "container", calculate utilization based on child prefixes. For all others, count child IP addresses.
        r   r   c                     g | ]	}|j         
S r%   r   r   s     r0   r   z*Prefix.get_utilization.<locals>.<listcomp>  s    +G+G+GAH+G+G+Gr2   c                     g | ]	}|j         
S r%   )r  r   rF   s     r0   r   z*Prefix.get_utilization.<locals>.<listcomp>  s    :::Q:::r2   c                 &    g | ]}|j         j        S r%   r  r  s     r0   r   z*Prefix.get_utilization.<locals>.<listcomp>  s    =i=i=iqail=i=i=ir2   r  r	     )r   r   r   r   r   r(   r)   r&   r"   r!   r+   r,   r   r   r   r   ry   rq   r   r   )r-   r   r/   r   r  prefix_sizes         r0   r   zPrefix.get_utilization  sJ   
  	3;->>>~,,&)$+&6&6H -  H %]+G+Gh+G+G+GHHN 344t{7GG#MKK  ::$"7"7"9"9:::=i=iTXTfTfThTh=i=i=ii I +*K{"a''DK,AB,F,Ft|,Fq 	//+=CK;$$$r2   )F)7r7   r8   r9   rP   r   rF   r"   r   r   r   r   r!   r^   r   	CharFieldr   STATUS_ACTIVEr   SET_NULLr   rQ   r   r   r   r   PositiveBigIntegerFieldr   r   
as_managerr(   r   rH   r   rg   rO   rp   r   r   rz   r   r   r   r   prefix_lengthr   r   r   r   r|   r   r   r  r  r   r   r   s   @r0   r   r      s'        
 ^Qx[[!455  F 6.  D &
.QuXX  C V.  F 6.  D V##1Qx[[!788  F 6/!9::  D "f!Q{^^!OPP  G
 (F'Q''!-..  M .V-  F /.  I
 (n'))GL, , , , , , , ,
3 3 3 3 3     6 6 6    .& & & & & < < X< > > X>   X   X* * * H"4555M; ; ;      ` ` `_ _ _
 
 
h h h  <U U U% % % % % % %r2   r   c            
       "    e Zd ZdZ e ed           ed                    Z e ed           ed                    Z ej	         ed          d          Z
 ej        d	ej        d
dd ed                    Z ej        dej        d
dd          Z ej         ed          deej         ed                    Z ej        dej        d
dd ed                    Z ej         ed          d ed                    ZdZ G d d          Zd Zd Z fdZ fd Zed!             Zed"             Zed#             Z e!d$             Z"d% Z# ee#&          Z$d' Z%d( Z&d) Z'e!d*             Z(e!d+             Z) xZ*S ),r   zF
    A range of IP addresses, defined by start and end addresses.
    zstart address IPv4 or IPv6 address (with mask)r   zend addressr   F)r=   r   r   	ip_rangesTr   r   rY   rZ   r   r   z Operational status of this ranger=   r   r   r<   r>   r   z"The primary function of this ranger   r   r   r   )r!   r^   r   r   r`   c                   ~    e Zd Z ed                              d          ddfZ ed          Z ed          ZdS )	IPRange.Metar!   Tr   start_addressrM   zIP rangez	IP rangesNr   r%   r2   r0   rH   r*  "  sM        AeHHLLTL22OTJq}}annr2   rH   c                     | j         S re   rA   rN   s    r0   rg   zIPRange.__str__'  r   r2   c                 0    t          d| j        g          S )Nzipam:iprangerJ   rL   rN   s    r0   rO   zIPRange.get_absolute_url*  s    ~TWI6666r2   c                 t   t                                                       | j        r
| j        r| j        j        | j        j        k    rt          dt          d          i          | j        j        | j        j        k    rt          dt          d          i          | j        | j        k    s7t          dt          d                              | j                  i          t          j
                            | j                                      | j                                      t          | j        | j                  t          | j        | j        	          z  t          | j        | j        
          z                                            }|r6t          t          d                              || j                            d}t#          | j        j        | j        j        z
            dz   |k    r4t          t          d                              |                    d S d S d S )Nend_addressz2Starting and ending IP address versions must matchz/Starting and ending IP address masks must matchzJEnding address must be greater than the starting address ({start_address}))r+  rm   r   )start_address__gtestart_address__lte)end_address__gteend_address__lte)r1  r2  zEDefined addresses overlap with range {overlapping_range} in VRF {vrf})overlapping_ranger!   l       z9Defined range exceeds maximum supported size ({max_size}))max_size)ro   rp   r+  r/  ry   r   rF   rq   rs   r   r(   rr   rM   r)   r!   Qr   intr  )r-   r4  MAX_SIZErv   s      r0   rp   zIPRange.clean-  sS    (	$"2 (	 !)T-=-EEE%!1%Y#Z#Z'   
 !+t/?/III%!1%V#W#W'   
 #d&888%!1d$ $f4+=f>>'    !( 7 747 7 C C J Jtx J X X _ _T%7DL\]]]4#5HXYYYZT%7$JZ[[[\! ! egg	 
 ! %]^^ee*; H f     #H4#&);)>>??!ChNN%QRRYYckYll  M(	 (	 (	 (	J ONr2   c                     t          | j        j        | j        j        z
            dz   | _         t                      j        |i | d S )Nr5  )r8  r/  r  r+  r   ro   r   r   s      r0   r   zIPRange.saveZ  sK     (+d.@.CCDDqH	d%f%%%%%r2   c                 ,    | j         r| j         j        nd S re   )r+  ry   rN   s    r0   rz   zIPRange.familya  s    -1-?It!))TIr2   c                 T    t          j        | j        j        | j        j                  S re   )r+   r   r+  r  r/  rN   s    r0   r  zIPRange.rangee  s     t14d6F6IJJJr2   c                 ,    | j         r| j         j        nd S re   )r+  rq   rN   s    r0   r   zIPRange.mask_lengthi  s    /3/AKt!++tKr2   c                 8   | j         dk    rdnd}t          | j        j                                      |          }t          | j        j                                      |          }g }t          ||          D ] \  }}||k    r|                    |           !|                    |          }|                    |t          |          d                   }|                    |t          |          d                   }	| | | d|	 d| j        j
         S )zL
        Return an efficient string representation of the IP range.
        r  :.N-/)rz   r&   r+  r  splitr/  zipr
  joinlenrq   )
r-   	separatorstart_chunks
end_chunksbase_chunksabbase_str	start_strend_strs
             r0   rB   zIPRange.namem  s    
  ;!++CC	4-01177	BB),--33I>>
j11 	& 	&DAqAvv""1%%%>>+..NN<K0@0@0A0A#BCC	..C,<,<,=,=!>??[I[y[[7[[T=O=Y[[[r2   c                 6    || j         _        || j        _        dS )z
        Expose the IPRange object's prefixlen attribute on the parent model so that it can be manipulated directly,
        e.g. for bulk editing.
        N)r+  rq   r/  r   s     r0   r   zIPRange._set_prefix_length  s     
 (-$%*"""r2   r   c                 J    t           j                            | j                  S re   )IPRangeStatusChoicesr   r   r   rN   s    r0   r   zIPRange.get_status_color  s    #*..t{;;;r2   c                 d    t           j                            | j        | j        | j                  S )zE
        Return all IPAddresses within this IPRange and VRF.
        )address__gteaddress__lter!   )r   r(   r)   r+  r/  r!   rN   s    r0   r   zIPRange.get_child_ips  s5      ''+) ( 
 
 	
r2   c                     t          j        | j        j        | j        j                  }t          j        d |                                 D                       }t          j        |          |z
  S )zI
        Return all available IPs within this range as an IPSet.
        c                 &    g | ]}|j         j        S r%   r  r  s     r0   r   z-IPRange.get_available_ips.<locals>.<listcomp>  r  r2   )r+   r   r+  r  r/  r,   r   )r-   r  r  s      r0   r  zIPRange.get_available_ips  s`      2 5t7G7JKKM"P"P4;M;M;O;O"P"P"PQQ	}U##i//r2   c                     |                                  }|sdS d                    t          |                                          | j        j                  S )zK
        Return the first available IP within the range (or None).
        Nr  )r  rs   r  r  r+  rq   r  s     r0   first_available_ipzIPRange.first_available_ip  sP    
 ..00 	4~~d=#9#9#;#;<<d>P>Z[[[r2   c                     | j         rdS t          j        d |                                 D                       j        }t          t          |          | j        z  dz  d          S )zW
        Determine the utilization of the range and return it as a percentage.
        r   c                 &    g | ]}|j         j        S r%   r  r  s     r0   r   z'IPRange.utilization.<locals>.<listcomp>  s)     %
 %
 %
 BJM%
 %
 %
r2   )r   r+   r,   r   r   r   r   )r-   child_counts     r0   r   zIPRange.utilization  s{    
  	3 m %
 %
$($6$6$8$8%
 %
 %
   	 5%%	1C7===r2   )+r7   r8   r9   rP   r   rF   r+  r/  r   PositiveIntegerFieldr   r   r   r!   r^   r  rR  r   r   r!  r   rQ   r   r   rH   rg   rO   rp   r   r   rz   r  r   r	   rB   r   r$  r   r   r  rY  r   r   r   s   @r0   r   r     sP         #NQ''!677  M !.Q}%%!677  K '6&QvYY  D &
. QuXX  C V.   F VQx[[$$2!677  F 6/ !899  D (F'Q''!-..  ML- - - - - - - -
  7 7 7+ + + + +Z& & & & & J J XJ K K XK L L XL \ \ _\&+ + + H"4555M< < <
 
 
0 0 0 \ \ _\ > > _> > > > >r2   r   c                       e Zd ZdZ e ed           ed                    Z ej        dej	        ddd ed          	          Z
 ej        d
ej	        ddd          Z ej         ed          deej         ed                    Z ej         ed          ded ed                    Z ej        deej	        ddd          Z ej        dd          Z edd          Z ej        dej        ddd ed           ed                    Z ej        ddeg ed            ed!          "          Z e            Zd#Z G d$ d%          Zd& Z  fd'Z!d( Z"d) Z#d* Z$d+ Z% fd,Z& fd-Z' fd.Z( fd/Z)e*d0             Z+e*d1             Z,e*d2             Z-d3 Z. e*e.4          Z/d5 Z0d6 Z1 xZ2S )7r   a  
    An IPAddress represents an individual IPv4 or IPv6 address and its mask. The mask length should match what is
    configured in the real world. (Typically, only loopback interfaces are configured with /32 or /128 masks.) Like
    Prefixes, IPAddresses can optionally be assigned to a VRF. An IPAddress can optionally be assigned to an Interface.
    Interfaces can have zero or more IPAddresses assigned to them.

    An IPAddress can also optionally point to a NAT inside IP, designating itself as a NAT outside IP. This is useful,
    for example, when mapping public addresses to private addresses. When an Interface has been assigned an IPAddress
    which has a NAT outside IP, that Interface's Device can use either the inside or outside IP as its primary IP.
    r  r&  r   r   ip_addressesTr   r   rY   rZ   r   r   z!The operational status of this IPr(  r   zThe functional role of this IP)r=   r   r   r[   r>   zcontenttypes.ContentType+)rV   limit_choices_torW   rX   r[   r\   )r[   r\   assigned_object_typeassigned_object_id)ct_fieldfk_fieldr-   nat_outsidezNAT (inside)z1The IP for which this address is the "outside" IP)rV   rW   rX   r[   r\   r=   r>      zDNS namez%Hostname or FQDN (not case-sensitive))r   r[   
validatorsr=   r>   )r!   r^   r   r   dns_namer`   c                       e Zd ZdZ ej         e ed           e                      d           ej        d          fZ	 e
d          Z e
d	          Zd
S )IPAddress.Meta)r  rM   r  )output_fieldipam_ipaddress_hostrA   )rb  rc  )fieldsz
IP addresszIP addressesN)r7   r8   r9   rE   r   Indexr   r   r   indexesrF   r=   rG   r%   r2   r0   rH   rk    s        $FLdd9ooNN<L<LMMMTijjjFL NOOO
 qa//r2   rH   c                 *    t          | j                  S re   )r&   r  rN   s    r0   rg   zIPAddress.__str__  s    4<   r2   c                      t                      j        |i | | j                            d          | _        | j                            d          | _        d S )Nrc  assigned_object_type_id)ro   r   r   r   _original_assigned_object_id!_original_assigned_object_type_idr   s      r0   r   zIPAddress.__init__  sY    $)&))) -1M,=,=>R,S,S)151B1BC\1]1]...r2   c                 0    t          d| j        g          S )Nzipam:ipaddressrJ   rL   rN   s    r0   rO   zIPAddress.get_absolute_url!  rj   r2   c                     t           j                            | j        t	          | j        j                                                | j                  S )N)r!   address__net_hostrm   )	r   r(   r)   r!   r&   r  r  rr   rM   rN   s    r0   r   zIPAddress.get_duplicates$  sI     ''!$,/22 ( 
 
 'TW'

	r2   c           	         | j         r| j         j        r| j         j        dz   }| j         j        dz
  }||k    rt          j        t          j        ||                    }|t          j        d t          j                            | j	        | j         | j         j
                                      dd          D                       z  }|r"t          t          |                    S dS dS dS dS )zX
        Return the next available IP address within this IP's network (if any)
        r5  c                     g | ]	}|j         
S r%   r  )r   r  s     r0   r   z3IPAddress.get_next_available_ip.<locals>.<listcomp>3  s'     0 0 0#*GJ0 0 0r2   )r!   address__gtaddress__net_contained_or_equalr  Tr#   N)r  	broadcastr  r+   r,   r   r   r(   r)   r!   r   r*   r  iter)r-   start_ipend_ipr  s       r0   get_next_available_ipzIPAddress.get_next_available_ip*  s    < 	5DL2 	5|*H\+a/F6!! 'goh.O.O P P 0 0.7.?.F.F H$(L8<8I /G / / "k)$k770 0 0 " "  ! 5] 3 3444	5 	5 	5 	5 "!5 5r2   c                     t           j                            t          | j                                                | j        t          | j                            S )zC
        Return all IPAddresses belonging to the same VRF.
        )r  )r!   r}  )r   r(   rr   r&   r  r)   r!   rN   s    r0   get_related_ipszIPAddress.get_related_ips=  sQ      ((T\1B1B(CCJJ#dl:K:K K 
 
 	
r2   c                 0   t                                                       | j        r8| j        j        dk    rt	          dt          d          i          | j        r| j        j        | j        j        k    rt          d          	                    | j        j                  }| j        j
        dk    r| j        j        dvrt	          |          | j        j
        dk    r| j        j        d	vrt	          |          | j        j
        dk    rd| j        j        | j        j        k    rJ| j        j        dvr<t          d
          	                    | j        j                  }t	          |          | j        t                      j        s| j        r| j        j        r|                                 }|r| j        t$          vst'          d |D                       r| j        r(t          d          	                    | j                  nt          d          }t	          dt          d          	                    ||                                          i          | j        r| j        rt/          | j        dd           }t0          j                            | j                  }|                    | j                  }t/          |dd           }d}| j        dk    r"t;          |d          r|j        | j        k    rd}| j        dk    r"t;          |d          r|j         | j        k    rd}|r"||k    rt	          t          d                    | j!        tD          j#        k    r)| j        dk    r t	          dt          d          i          d S d S )Nr   r  z&Cannot create IP address with /0 mask.z@{ip} is a network ID, which may not be assigned to an interface.r{  r  )r	      r  )r     zG{ip} is a broadcast address, which may not be assigned to an interface.c              3   2   K   | ]}|j         t          vV  d S re   )r   IPADDRESS_ROLES_NONUNIQUE)r   dips     r0   	<genexpr>z"IPAddress.clean.<locals>.<genexpr>h  s*      __#CH,EE______r2   r   r   r   z2Duplicate IP address found in {table}: {ipaddress})r   	ipaddressparent_objectrm   Fprimary_ip4Tprimary_ip6zYCannot reassign IP address while it is designated as the primary IP for the parent objectr   z0Only IPv6 addresses can be assigned SLAAC status)$ro   rp   r  rq   r   rF   assigned_objectr  networkrs   ry   r~  r!   r   r   r   r   r   r  anyr   rt  ru  getattrr   r(   
get_for_idget_object_for_this_typerz   r'   primary_ip4_idrM   primary_ip6_idr   IPAddressStatusChoicesSTATUS_SLAAC)
r-   msgduplicate_ipsr   parentctoriginal_assigned_objectoriginal_parent
is_primaryrv   s
            r0   rp   zIPAddress.cleanE  s   < (	 |%**%q!IJJ'   
 # /<?dl&:::^__ff<? g  C |+q00T\5KS[5[5[-c222|+q00T\5KS]5]5]-c222,11dloI_6_6_.h>>effmm<? n  C *#...  Z\\%G TX Z^ZbZq  $ 3 3 5 5  
	)BBB__Q^_____ C DH8bAkNN11dh1???QRSaQbQbE)!1%Y#Z#Z#a#a"'&3&9&9&;&; $b $ $+    , 	1W 	T1?DIIF#..t/UVVB')'B'BdFg'B'h'h$%&>QUVVO J{aGO]$K$KP_PnrvryPyPy!
{aGO]$K$KP_PnrvryPyPy!
 v88%qrr  
 ;0===$+QRBRBR!!NOO#    >=BRBRr2   c                 v    | j                                         | _          t                      j        |i | d S re   )ri  lowerro   r   r   s      r0   r   zIPAddress.save  s;     ++--d%f%%%%%r2   c                     t                                                      }|                                 x}r| d| j        j         |d<   |S )NrB  r  )ro   cloner  r  rq   )r-   attrsnext_available_iprv   s      r0   r  zIPAddress.clone  sS     !% : : < << 	O"3NNdl6LNNE)r2   c                 b    t                                          |          }| j        |_        |S re   )ro   to_objectchanger  related_object)r-   actionobjectchangerv   s      r0   r  zIPAddress.to_objectchange  s+    ww..v66&*&:#r2   c                 ,    | j         r| j         j        S d S re   )r  ry   rN   s    r0   rz   zIPAddress.family  s    < 	(<''tr2   c                     | j         r8t          | j         dd           }t          |d          r|j        | j        k    rdS dS )Nr  oob_ipTF)r  r  r'   	oob_ip_idrM   r-   r  s     r0   	is_oob_ipzIPAddress.is_oob_ip  sL     	T1?DIIFvx(( V-=-H-Htur2   c                     | j         rpt          | j         dd           }| j        dk    r"t          |d          r|j        | j        k    rdS | j        dk    r"t          |d          r|j        | j        k    rdS dS )Nr  r  r  Tr  r  F)r  r  rz   r'   r  rM   r  r  s     r0   is_primary_ipzIPAddress.is_primary_ip  s     	T1?DIIF{aGFM$B$BvG\`d`gGgGgt{aGFM$B$BvG\`d`gGgGgtur2   c                 0    | j         || j         _        dS dS r   )r  rq   r   s     r0   _set_mask_lengthzIPAddress._set_mask_length  s$    
 <#%*DL""" $#r2   r   c                 J    t           j                            | j                  S re   )r  r   r   r   rN   s    r0   r   zIPAddress.get_status_color  s    %,00===r2   c                 J    t           j                            | j                  S re   )IPAddressRoleChoicesr   r   r   rN   s    r0   get_role_colorzIPAddress.get_role_color  s    #*..ty999r2   )3r7   r8   r9   rP   r   rF   r  r   r   r   r!   r^   r  r  r   r   r  r   IPADDRESS_ASSIGNMENT_MODELSrb  r"  rc  r   r  r!  
nat_insider   ri  r   r(   r   rH   rg   r   rO   r   r  r  rp   r   r  r  r   rz   r  r  r  r   r   r  r   r   s   @r0   r   r     s       	 	 nQy\\!677  G &
.#QuXX  C V.#  F VQx[[&&4!788  F 6QvYY$!455  D -6,%4.   87   (''%  O #"/"Q~&&!GHH  J  v >Qz]]!;<<  H   GL0 0 0 0 0 0 0 0! ! !^ ^ ^ ^ ^9 9 9  5 5 5&
 
 
C C C C CJ& & & & &        
   X
   X   X+ + + ( 0111K> > >: : : : : : :r2   r   )0r+   "django.contrib.contenttypes.fieldsr   django.core.exceptionsr   	django.dbr   django.db.modelsr   django.db.models.functionsr   django.urlsr   django.utils.functionalr	   django.utils.translationr
   rF   core.modelsr   ipam.choicesipam.constantsipam.fieldsr   r   ipam.lookupsr   ipam.managersr   ipam.querysetsr   ipam.validatorsr   netbox.configr   netbox.modelsr   r   netbox.models.featuresr   __all__r   r   r   r   r   r   r   r%   r2   r0   <module>r     s    @ @ @ @ @ @ 2 2 2 2 2 2             + + + + + +       3 3 3 3 3 3 6 6 6 6 6 6 " " " " " "         6 6 6 6 6 6 6 6       * * * * * * ) ) ) ) ) ) ( ( ( ( ( ( $ $ $ $ $ $ ; ; ; ; ; ; ; ; 0 0 0 0 0 02 2 2 2 2 2 2 223 3 3 3 3
 3 3 3(k% k% k% k% k%8, k% k% k%\4 4 4 4 4 4 4 4,U% U% U% U% U%]5| U% U% U%pN> N> N> N> N>m\ N> N> N>bI: I: I: I: I:| I: I: I: I: I:r2   