1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.connectivity.mdns;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 
21 /**
22  * The class that contains mDNS feature flags;
23  */
24 public class MdnsFeatureFlags {
25     /**
26      * A feature flag to control whether the mDNS offload is enabled or not.
27      */
28     public static final String NSD_FORCE_DISABLE_MDNS_OFFLOAD = "nsd_force_disable_mdns_offload";
29 
30     /**
31      * A feature flag to control whether the probing question should include
32      * InetAddressRecords or not.
33      */
34     public static final String INCLUDE_INET_ADDRESS_RECORDS_IN_PROBING =
35             "include_inet_address_records_in_probing";
36     /**
37      * A feature flag to control whether expired services removal should be enabled.
38      */
39     public static final String NSD_EXPIRED_SERVICES_REMOVAL =
40             "nsd_expired_services_removal";
41 
42     /**
43      * A feature flag to control whether the label count limit should be enabled.
44      */
45     public static final String NSD_LIMIT_LABEL_COUNT = "nsd_limit_label_count";
46 
47     /**
48      * A feature flag to control whether the known-answer suppression should be enabled.
49      */
50     public static final String NSD_KNOWN_ANSWER_SUPPRESSION = "nsd_known_answer_suppression";
51 
52     /**
53      * A feature flag to control whether unicast replies should be enabled.
54      *
55      * <p>Enabling this feature causes replies to queries with the Query Unicast (QU) flag set to be
56      * sent unicast instead of multicast, as per RFC6762 5.4.
57      */
58     public static final String NSD_UNICAST_REPLY_ENABLED = "nsd_unicast_reply_enabled";
59 
60     /**
61      * A feature flag to control whether the aggressive query mode should be enabled.
62      */
63     public static final String NSD_AGGRESSIVE_QUERY_MODE = "nsd_aggressive_query_mode";
64 
65     /**
66      * A feature flag to control whether the query with known-answer should be enabled.
67      */
68     public static final String NSD_QUERY_WITH_KNOWN_ANSWER = "nsd_query_with_known_answer";
69 
70     // Flag for offload feature
71     public final boolean mIsMdnsOffloadFeatureEnabled;
72 
73     // Flag for including InetAddressRecords in probing questions.
74     public final boolean mIncludeInetAddressRecordsInProbing;
75 
76     // Flag for expired services removal
77     public final boolean mIsExpiredServicesRemovalEnabled;
78 
79     // Flag for label count limit
80     public final boolean mIsLabelCountLimitEnabled;
81 
82     // Flag for known-answer suppression
83     public final boolean mIsKnownAnswerSuppressionEnabled;
84 
85     // Flag to enable replying unicast to queries requesting unicast replies
86     public final boolean mIsUnicastReplyEnabled;
87 
88     // Flag for aggressive query mode
89     public final boolean mIsAggressiveQueryModeEnabled;
90 
91     // Flag for query with known-answer
92     public final boolean mIsQueryWithKnownAnswerEnabled;
93 
94     @Nullable
95     private final FlagOverrideProvider mOverrideProvider;
96 
97     /**
98      * A provider that can indicate whether a flag should be force-enabled for testing purposes.
99      */
100     public interface FlagOverrideProvider {
101         /**
102          * Indicates whether the flag should be force-enabled for testing purposes.
103          */
isForceEnabledForTest(@onNull String flag)104         boolean isForceEnabledForTest(@NonNull String flag);
105     }
106 
107     /**
108      * Indicates whether the flag should be force-enabled for testing purposes.
109      */
isForceEnabledForTest(@onNull String flag)110     private boolean isForceEnabledForTest(@NonNull String flag) {
111         return mOverrideProvider != null && mOverrideProvider.isForceEnabledForTest(flag);
112     }
113 
114     /**
115      * Indicates whether {@link #NSD_UNICAST_REPLY_ENABLED} is enabled, including for testing.
116      */
isUnicastReplyEnabled()117     public boolean isUnicastReplyEnabled() {
118         return mIsUnicastReplyEnabled || isForceEnabledForTest(NSD_UNICAST_REPLY_ENABLED);
119     }
120 
121     /**
122      * Indicates whether {@link #NSD_AGGRESSIVE_QUERY_MODE} is enabled, including for testing.
123      */
isAggressiveQueryModeEnabled()124     public boolean isAggressiveQueryModeEnabled() {
125         return mIsAggressiveQueryModeEnabled || isForceEnabledForTest(NSD_AGGRESSIVE_QUERY_MODE);
126     }
127 
128     /**
129      * Indicates whether {@link #NSD_KNOWN_ANSWER_SUPPRESSION} is enabled, including for testing.
130      */
isKnownAnswerSuppressionEnabled()131     public boolean isKnownAnswerSuppressionEnabled() {
132         return mIsKnownAnswerSuppressionEnabled
133                 || isForceEnabledForTest(NSD_KNOWN_ANSWER_SUPPRESSION);
134     }
135 
136     /**
137      * Indicates whether {@link #NSD_QUERY_WITH_KNOWN_ANSWER} is enabled, including for testing.
138      */
isQueryWithKnownAnswerEnabled()139     public boolean isQueryWithKnownAnswerEnabled() {
140         return mIsQueryWithKnownAnswerEnabled
141                 || isForceEnabledForTest(NSD_QUERY_WITH_KNOWN_ANSWER);
142     }
143 
144     /**
145      * The constructor for {@link MdnsFeatureFlags}.
146      */
MdnsFeatureFlags(boolean isOffloadFeatureEnabled, boolean includeInetAddressRecordsInProbing, boolean isExpiredServicesRemovalEnabled, boolean isLabelCountLimitEnabled, boolean isKnownAnswerSuppressionEnabled, boolean isUnicastReplyEnabled, boolean isAggressiveQueryModeEnabled, boolean isQueryWithKnownAnswerEnabled, @Nullable FlagOverrideProvider overrideProvider)147     public MdnsFeatureFlags(boolean isOffloadFeatureEnabled,
148             boolean includeInetAddressRecordsInProbing,
149             boolean isExpiredServicesRemovalEnabled,
150             boolean isLabelCountLimitEnabled,
151             boolean isKnownAnswerSuppressionEnabled,
152             boolean isUnicastReplyEnabled,
153             boolean isAggressiveQueryModeEnabled,
154             boolean isQueryWithKnownAnswerEnabled,
155             @Nullable FlagOverrideProvider overrideProvider) {
156         mIsMdnsOffloadFeatureEnabled = isOffloadFeatureEnabled;
157         mIncludeInetAddressRecordsInProbing = includeInetAddressRecordsInProbing;
158         mIsExpiredServicesRemovalEnabled = isExpiredServicesRemovalEnabled;
159         mIsLabelCountLimitEnabled = isLabelCountLimitEnabled;
160         mIsKnownAnswerSuppressionEnabled = isKnownAnswerSuppressionEnabled;
161         mIsUnicastReplyEnabled = isUnicastReplyEnabled;
162         mIsAggressiveQueryModeEnabled = isAggressiveQueryModeEnabled;
163         mIsQueryWithKnownAnswerEnabled = isQueryWithKnownAnswerEnabled;
164         mOverrideProvider = overrideProvider;
165     }
166 
167 
168     /** Returns a {@link Builder} for {@link MdnsFeatureFlags}. */
newBuilder()169     public static Builder newBuilder() {
170         return new Builder();
171     }
172 
173     /** A builder to create {@link MdnsFeatureFlags}. */
174     public static final class Builder {
175 
176         private boolean mIsMdnsOffloadFeatureEnabled;
177         private boolean mIncludeInetAddressRecordsInProbing;
178         private boolean mIsExpiredServicesRemovalEnabled;
179         private boolean mIsLabelCountLimitEnabled;
180         private boolean mIsKnownAnswerSuppressionEnabled;
181         private boolean mIsUnicastReplyEnabled;
182         private boolean mIsAggressiveQueryModeEnabled;
183         private boolean mIsQueryWithKnownAnswerEnabled;
184         private FlagOverrideProvider mOverrideProvider;
185 
186         /**
187          * The constructor for {@link Builder}.
188          */
Builder()189         public Builder() {
190             mIsMdnsOffloadFeatureEnabled = false;
191             mIncludeInetAddressRecordsInProbing = false;
192             mIsExpiredServicesRemovalEnabled = true; // Default enabled.
193             mIsLabelCountLimitEnabled = true; // Default enabled.
194             mIsKnownAnswerSuppressionEnabled = true; // Default enabled.
195             mIsUnicastReplyEnabled = true; // Default enabled.
196             mIsAggressiveQueryModeEnabled = false;
197             mIsQueryWithKnownAnswerEnabled = false;
198             mOverrideProvider = null;
199         }
200 
201         /**
202          * Set whether the mDNS offload feature is enabled.
203          *
204          * @see #NSD_FORCE_DISABLE_MDNS_OFFLOAD
205          */
setIsMdnsOffloadFeatureEnabled(boolean isMdnsOffloadFeatureEnabled)206         public Builder setIsMdnsOffloadFeatureEnabled(boolean isMdnsOffloadFeatureEnabled) {
207             mIsMdnsOffloadFeatureEnabled = isMdnsOffloadFeatureEnabled;
208             return this;
209         }
210 
211         /**
212          * Set whether the probing question should include InetAddressRecords.
213          *
214          * @see #INCLUDE_INET_ADDRESS_RECORDS_IN_PROBING
215          */
setIncludeInetAddressRecordsInProbing( boolean includeInetAddressRecordsInProbing)216         public Builder setIncludeInetAddressRecordsInProbing(
217                 boolean includeInetAddressRecordsInProbing) {
218             mIncludeInetAddressRecordsInProbing = includeInetAddressRecordsInProbing;
219             return this;
220         }
221 
222         /**
223          * Set whether the expired services removal is enabled.
224          *
225          * @see #NSD_EXPIRED_SERVICES_REMOVAL
226          */
setIsExpiredServicesRemovalEnabled(boolean isExpiredServicesRemovalEnabled)227         public Builder setIsExpiredServicesRemovalEnabled(boolean isExpiredServicesRemovalEnabled) {
228             mIsExpiredServicesRemovalEnabled = isExpiredServicesRemovalEnabled;
229             return this;
230         }
231 
232         /**
233          * Set whether the label count limit is enabled.
234          *
235          * @see #NSD_LIMIT_LABEL_COUNT
236          */
setIsLabelCountLimitEnabled(boolean isLabelCountLimitEnabled)237         public Builder setIsLabelCountLimitEnabled(boolean isLabelCountLimitEnabled) {
238             mIsLabelCountLimitEnabled = isLabelCountLimitEnabled;
239             return this;
240         }
241 
242         /**
243          * Set whether the known-answer suppression is enabled.
244          *
245          * @see #NSD_KNOWN_ANSWER_SUPPRESSION
246          */
setIsKnownAnswerSuppressionEnabled(boolean isKnownAnswerSuppressionEnabled)247         public Builder setIsKnownAnswerSuppressionEnabled(boolean isKnownAnswerSuppressionEnabled) {
248             mIsKnownAnswerSuppressionEnabled = isKnownAnswerSuppressionEnabled;
249             return this;
250         }
251 
252         /**
253          * Set whether the unicast reply feature is enabled.
254          *
255          * @see #NSD_UNICAST_REPLY_ENABLED
256          */
setIsUnicastReplyEnabled(boolean isUnicastReplyEnabled)257         public Builder setIsUnicastReplyEnabled(boolean isUnicastReplyEnabled) {
258             mIsUnicastReplyEnabled = isUnicastReplyEnabled;
259             return this;
260         }
261 
262         /**
263          * Set a {@link FlagOverrideProvider} to be used by {@link #isForceEnabledForTest(String)}.
264          *
265          * If non-null, features that use {@link #isForceEnabledForTest(String)} will use that
266          * provider to query whether the flag should be force-enabled.
267          */
setOverrideProvider(@ullable FlagOverrideProvider overrideProvider)268         public Builder setOverrideProvider(@Nullable FlagOverrideProvider overrideProvider) {
269             mOverrideProvider = overrideProvider;
270             return this;
271         }
272 
273         /**
274          * Set whether the aggressive query mode is enabled.
275          *
276          * @see #NSD_AGGRESSIVE_QUERY_MODE
277          */
setIsAggressiveQueryModeEnabled(boolean isAggressiveQueryModeEnabled)278         public Builder setIsAggressiveQueryModeEnabled(boolean isAggressiveQueryModeEnabled) {
279             mIsAggressiveQueryModeEnabled = isAggressiveQueryModeEnabled;
280             return this;
281         }
282 
283         /**
284          * Set whether the query with known-answer is enabled.
285          *
286          * @see #NSD_QUERY_WITH_KNOWN_ANSWER
287          */
setIsQueryWithKnownAnswerEnabled(boolean isQueryWithKnownAnswerEnabled)288         public Builder setIsQueryWithKnownAnswerEnabled(boolean isQueryWithKnownAnswerEnabled) {
289             mIsQueryWithKnownAnswerEnabled = isQueryWithKnownAnswerEnabled;
290             return this;
291         }
292 
293         /**
294          * Builds a {@link MdnsFeatureFlags} with the arguments supplied to this builder.
295          */
build()296         public MdnsFeatureFlags build() {
297             return new MdnsFeatureFlags(mIsMdnsOffloadFeatureEnabled,
298                     mIncludeInetAddressRecordsInProbing,
299                     mIsExpiredServicesRemovalEnabled,
300                     mIsLabelCountLimitEnabled,
301                     mIsKnownAnswerSuppressionEnabled,
302                     mIsUnicastReplyEnabled,
303                     mIsAggressiveQueryModeEnabled,
304                     mIsQueryWithKnownAnswerEnabled,
305                     mOverrideProvider);
306         }
307     }
308 }
309